00001 /****************************************************************************** 00002 * 00003 * $Id: doxygen.cpp,v 1.87 2001/03/19 19:27:40 root Exp $ 00004 * 00005 * 00006 * Copyright (C) 1997-2008 by Dimitri van Heesch. 00007 * 00008 * Permission to use, copy, modify, and distribute this software and its 00009 * documentation under the terms of the GNU General Public License is hereby 00010 * granted. No representations are made about the suitability of this software 00011 * for any purpose. It is provided "as is" without express or implied warranty. 00012 * See the GNU General Public License for more details. 00013 * 00014 * Documents produced by Doxygen are derivative works derived from the 00015 * input used in their production; they are not affected by this license. 00016 * 00017 */ 00018 00019 #include "qtbc.h" 00020 #include <qfileinfo.h> 00021 #include <qfile.h> 00022 #include <qdir.h> 00023 #include <qdict.h> 00024 #include <qregexp.h> 00025 #include <qstrlist.h> 00026 #include <stdio.h> 00027 #include <stdlib.h> 00028 #include <sys/stat.h> 00029 #include <qtextcodec.h> 00030 #include <unistd.h> 00031 #include <errno.h> 00032 00033 #include "version.h" 00034 #include "doxygen.h" 00035 #include "scanner.h" 00036 #include "entry.h" 00037 #include "index.h" 00038 #include "logos.h" 00039 #include "instdox.h" 00040 #include "message.h" 00041 #include "config.h" 00042 #include "util.h" 00043 #include "pre.h" 00044 #include "tagreader.h" 00045 #include "dot.h" 00046 #include "docparser.h" 00047 #include "dirdef.h" 00048 #include "outputlist.h" 00049 #include "declinfo.h" 00050 #include "htmlgen.h" 00051 #include "latexgen.h" 00052 #include "mangen.h" 00053 #include "language.h" 00054 #include "debug.h" 00055 #include "htmlhelp.h" 00056 #include "ftvhelp.h" 00057 #include "defargs.h" 00058 #include "rtfgen.h" 00059 #include "xmlgen.h" 00060 #include "defgen.h" 00061 #include "perlmodgen.h" 00062 #include "reflist.h" 00063 #include "pagedef.h" 00064 #include "bufstr.h" 00065 #include "commentcnv.h" 00066 #include "cmdmapper.h" 00067 #include "searchindex.h" 00068 #include "parserintf.h" 00069 #include "htags.h" 00070 #include "pyscanner.h" 00071 #include "fortranscanner.h" 00072 #include "code.h" 00073 #include "objcache.h" 00074 #include "store.h" 00075 #include "marshal.h" 00076 #include "portable.h" 00077 #include "vhdlscanner.h" 00078 00079 #define RECURSE_ENTRYTREE(func,var) \ 00080 do { if (var->children()) { \ 00081 EntryNavListIterator eli(*var->children()); \ 00082 for (;eli.current();++eli) func(eli.current()); \ 00083 } } while(0) 00084 00085 00086 #if !defined(_WIN32) || defined(__CYGWIN__) 00087 #include <signal.h> 00088 #define HAS_SIGNALS 00089 #endif 00090 00091 // globally accessible variables 00092 ClassSDict *Doxygen::classSDict = 0; 00093 ClassSDict *Doxygen::hiddenClasses = 0; 00094 NamespaceSDict *Doxygen::namespaceSDict = 0; 00095 MemberNameSDict *Doxygen::memberNameSDict = 0; 00096 MemberNameSDict *Doxygen::functionNameSDict = 0; 00097 FileNameList *Doxygen::inputNameList = 0; // all input files 00098 FileNameDict *Doxygen::inputNameDict = 0; 00099 GroupSDict *Doxygen::groupSDict = 0; 00100 FormulaList Doxygen::formulaList; // all formulas 00101 FormulaDict Doxygen::formulaDict(1009); // all formulas 00102 FormulaDict Doxygen::formulaNameDict(1009); // the label name of all formulas 00103 PageSDict *Doxygen::pageSDict = 0; 00104 PageSDict *Doxygen::exampleSDict = 0; 00105 SectionDict Doxygen::sectionDict(257); // all page sections 00106 StringDict Doxygen::aliasDict(257); // aliases 00107 FileNameDict *Doxygen::includeNameDict = 0; // include names 00108 FileNameDict *Doxygen::exampleNameDict = 0; // examples 00109 FileNameDict *Doxygen::imageNameDict = 0; // images 00110 FileNameDict *Doxygen::dotFileNameDict = 0; // dot files 00111 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases 00112 StringDict Doxygen::tagDestinationDict(257); // all tag locations 00113 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded 00114 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading 00115 PageDef *Doxygen::mainPage = 0; 00116 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page? 00117 QTextStream Doxygen::tagFile; 00118 NamespaceDef *Doxygen::globalScope = 0; 00119 QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists 00120 bool Doxygen::parseSourcesNeeded = FALSE; 00121 double Doxygen::sysElapsedTime = 0.0; 00122 QTime Doxygen::runningTime; 00123 SearchIndex * Doxygen::searchIndex=0; 00124 QDict<DefinitionIntf> *Doxygen::symbolMap; 00125 bool Doxygen::outputToWizard=FALSE; 00126 QDict<int> * Doxygen::htmlDirMap = 0; 00127 QCache<LookupInfo> Doxygen::lookupCache(50000,50000); 00128 DirSDict *Doxygen::directories; 00129 SDict<DirRelation> Doxygen::dirRelations(257); 00130 ParserManager *Doxygen::parserManager = 0; 00131 QCString Doxygen::htmlFileExtension; 00132 bool Doxygen::suppressDocWarnings = FALSE; 00133 ObjCache *Doxygen::symbolCache = 0; 00134 Store *Doxygen::symbolStorage; 00135 QCString Doxygen::objDBFileName; 00136 QCString Doxygen::entryDBFileName; 00137 bool Doxygen::gatherDefines = TRUE; 00138 IndexList Doxygen::indexList; 00139 00140 bool Doxygen::userComments = FALSE; 00141 00142 // locally accessible globals 00143 static QDict<EntryNav> classEntries(1009); 00144 static StringList inputFiles; 00145 static StringDict excludeNameDict(1009); // sections 00146 static QDict<void> compoundKeywordDict(7); // keywords recognised as compounds 00147 static OutputList *outputList = 0; // list of output generating objects 00148 static QDict<FileDef> g_usingDeclarations(1009); // used classes 00149 static const char idMask[] = "[A-Za-z_][A-Za-z_0-9]*"; 00150 00151 FileStorage *g_storage = 0; 00152 00153 QCString spaces; 00154 00155 static bool g_successfulRun = FALSE; 00156 static bool g_dumpSymbolMap = FALSE; 00157 00158 00159 00160 void clearAll() 00161 { 00162 inputFiles.clear(); 00163 excludeNameDict.clear(); 00164 delete outputList; outputList=0; 00165 00166 Doxygen::classSDict->clear(); 00167 Doxygen::namespaceSDict->clear(); 00168 Doxygen::pageSDict->clear(); 00169 Doxygen::exampleSDict->clear(); 00170 Doxygen::inputNameList->clear(); 00171 Doxygen::formulaList.clear(); 00172 Doxygen::sectionDict.clear(); 00173 Doxygen::inputNameDict->clear(); 00174 Doxygen::includeNameDict->clear(); 00175 Doxygen::exampleNameDict->clear(); 00176 Doxygen::imageNameDict->clear(); 00177 Doxygen::dotFileNameDict->clear(); 00178 Doxygen::formulaDict.clear(); 00179 Doxygen::formulaNameDict.clear(); 00180 Doxygen::tagDestinationDict.clear(); 00181 delete Doxygen::mainPage; Doxygen::mainPage=0; 00182 } 00183 00184 void statistics() 00185 { 00186 fprintf(stderr,"--- inputNameDict stats ----\n"); 00187 Doxygen::inputNameDict->statistics(); 00188 fprintf(stderr,"--- includeNameDict stats ----\n"); 00189 Doxygen::includeNameDict->statistics(); 00190 fprintf(stderr,"--- exampleNameDict stats ----\n"); 00191 Doxygen::exampleNameDict->statistics(); 00192 fprintf(stderr,"--- imageNameDict stats ----\n"); 00193 Doxygen::imageNameDict->statistics(); 00194 fprintf(stderr,"--- dotFileNameDict stats ----\n"); 00195 Doxygen::dotFileNameDict->statistics(); 00196 fprintf(stderr,"--- excludeNameDict stats ----\n"); 00197 excludeNameDict.statistics(); 00198 fprintf(stderr,"--- aliasDict stats ----\n"); 00199 Doxygen::aliasDict.statistics(); 00200 fprintf(stderr,"--- typedefDict stats ----\n"); 00201 fprintf(stderr,"--- namespaceAliasDict stats ----\n"); 00202 Doxygen::namespaceAliasDict.statistics(); 00203 fprintf(stderr,"--- formulaDict stats ----\n"); 00204 Doxygen::formulaDict.statistics(); 00205 fprintf(stderr,"--- formulaNameDict stats ----\n"); 00206 Doxygen::formulaNameDict.statistics(); 00207 fprintf(stderr,"--- tagDestinationDict stats ----\n"); 00208 Doxygen::tagDestinationDict.statistics(); 00209 fprintf(stderr,"--- compoundKeywordDict stats ----\n"); 00210 compoundKeywordDict.statistics(); 00211 fprintf(stderr,"--- expandAsDefinedDict stats ----\n"); 00212 Doxygen::expandAsDefinedDict.statistics(); 00213 fprintf(stderr,"--- memGrpInfoDict stats ----\n"); 00214 Doxygen::memGrpInfoDict.statistics(); 00215 } 00216 00217 00218 00219 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl, 00220 ArgumentList *al,bool over_load,NamespaceSDict *nl=0); 00221 static void findMember(EntryNav *rootNav, 00222 QCString funcDecl, 00223 bool overloaded, 00224 bool isFunc 00225 ); 00226 00227 00228 struct STLInfo 00229 { 00230 const char *className; 00231 const char *baseClass1; 00232 const char *baseClass2; 00233 const char *templType1; 00234 const char *templName1; 00235 const char *templType2; 00236 const char *templName2; 00237 bool virtualInheritance; 00238 bool iterators; 00239 }; 00240 00241 static STLInfo g_stlinfo[] = 00242 { 00243 // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators 00244 #if 0 00245 { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, 00246 { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, 00247 { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, 00248 { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE }, 00249 { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE }, 00250 { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE }, 00251 { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE }, 00252 { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, 00253 { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, 00254 { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, 00255 { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, 00256 { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, 00257 { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, 00258 { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00259 { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00260 { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00261 { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00262 { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00263 { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00264 { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00265 { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00266 { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00267 { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00268 { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00269 { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00270 { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00271 { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00272 { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00273 { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00274 { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00275 { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, 00276 { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE }, 00277 { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE }, 00278 { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE }, 00279 { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, 00280 { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE }, 00281 { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, 00282 { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, 00283 { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, 00284 { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, 00285 { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, 00286 { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, 00287 #endif 00288 { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, 00289 #if 0 00290 { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, 00291 { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, 00292 { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, 00293 { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, 00294 { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, 00295 { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, 00296 { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, 00297 { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, 00298 { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, 00299 { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, 00300 { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, 00301 { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, 00302 { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, 00303 { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, 00304 { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, 00305 { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, 00306 { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, 00307 { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, 00308 { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, 00309 #endif 00310 { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE } 00311 }; 00312 00313 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name) 00314 { 00315 Entry *memEntry = new Entry; 00316 memEntry->name = name; 00317 memEntry->type = type; 00318 memEntry->protection = Private; 00319 memEntry->section = Entry::VARIABLE_SEC; 00320 memEntry->brief = "STL member"; 00321 memEntry->hidden = FALSE; 00322 memEntry->artificial = TRUE; 00323 //memEntry->parent = root; 00324 //root->addSubEntry(memEntry); 00325 EntryNav *memEntryNav = new EntryNav(rootNav,memEntry); 00326 memEntryNav->setEntry(memEntry); 00327 rootNav->addChild(memEntryNav); 00328 } 00329 00330 static void addSTLIterator(EntryNav *classEntryNav,const char *name) 00331 { 00332 Entry *iteratorClassEntry = new Entry; 00333 iteratorClassEntry->fileName = "[STL]"; 00334 iteratorClassEntry->startLine = 1; 00335 iteratorClassEntry->name = name; 00336 iteratorClassEntry->section = Entry::CLASS_SEC; 00337 iteratorClassEntry->brief = "STL iterator class"; 00338 iteratorClassEntry->hidden = FALSE; 00339 iteratorClassEntry->artificial= TRUE; 00340 EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry); 00341 iteratorClassEntryNav->setEntry(iteratorClassEntry); 00342 classEntryNav->addChild(iteratorClassEntryNav); 00343 } 00344 00345 00346 static void addSTLClasses(EntryNav *rootNav) 00347 { 00348 Entry *namespaceEntry = new Entry; 00349 namespaceEntry->fileName = "[STL]"; 00350 namespaceEntry->startLine = 1; 00351 //namespaceEntry->parent = rootNav->entry(); 00352 namespaceEntry->name = "std"; 00353 namespaceEntry->section = Entry::NAMESPACE_SEC; 00354 namespaceEntry->brief = "STL namespace"; 00355 namespaceEntry->hidden = FALSE; 00356 namespaceEntry->artificial= TRUE; 00357 //root->addSubEntry(namespaceEntry); 00358 EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry); 00359 namespaceEntryNav->setEntry(namespaceEntry); 00360 rootNav->addChild(namespaceEntryNav); 00361 00362 STLInfo *info = g_stlinfo; 00363 while (info->className) 00364 { 00365 //printf("Adding STL class %s\n",info->className); 00366 QCString fullName = info->className; 00367 fullName.prepend("std::"); 00368 00369 // add fake Entry for the class 00370 Entry *classEntry = new Entry; 00371 classEntry->fileName = "[STL]"; 00372 classEntry->startLine = 1; 00373 classEntry->name = fullName; 00374 //classEntry->parent = namespaceEntry; 00375 classEntry->section = Entry::CLASS_SEC; 00376 classEntry->brief = "STL class"; 00377 classEntry->hidden = FALSE; 00378 classEntry->artificial= TRUE; 00379 //namespaceEntry->addSubEntry(classEntry); 00380 EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry); 00381 classEntryNav->setEntry(classEntry); 00382 namespaceEntryNav->addChild(classEntryNav); 00383 00384 // add template arguments to class 00385 if (info->templType1) 00386 { 00387 ArgumentList *al = new ArgumentList; 00388 Argument *a=new Argument; 00389 a->type="typename"; 00390 a->name=info->templType1; 00391 al->append(a); 00392 if (info->templType2) // another template argument 00393 { 00394 a=new Argument; 00395 a->type="typename"; 00396 a->name=info->templType2; 00397 al->append(a); 00398 } 00399 classEntry->tArgLists = new QList<ArgumentList>; 00400 classEntry->tArgLists->setAutoDelete(TRUE); 00401 classEntry->tArgLists->append(al); 00402 } 00403 // add member variables 00404 if (info->templName1) 00405 { 00406 addSTLMember(classEntryNav,info->templType1,info->templName1); 00407 } 00408 if (info->templName2) 00409 { 00410 addSTLMember(classEntryNav,info->templType2,info->templName2); 00411 } 00412 if (info->baseClass1) 00413 { 00414 classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal)); 00415 } 00416 if (info->baseClass2) 00417 { 00418 classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal)); 00419 } 00420 if (info->iterators) 00421 { 00422 // add iterator class 00423 addSTLIterator(classEntryNav,fullName+"::iterator"); 00424 addSTLIterator(classEntryNav,fullName+"::const_iterator"); 00425 addSTLIterator(classEntryNav,fullName+"::reverse_iterator"); 00426 addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator"); 00427 } 00428 info++; 00429 } 00430 } 00431 00432 //---------------------------------------------------------------------------- 00433 00434 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n, 00435 FileDef *fileScope=0); 00436 00437 static void addPageToContext(PageDef *pd,EntryNav *rootNav) 00438 { 00439 if (rootNav->parent()) // add the page to it's scope 00440 { 00441 QCString scope = rootNav->parent()->name(); 00442 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC) 00443 { 00444 scope=substitute(scope,".","::"); 00445 } 00446 scope = stripAnonymousNamespaceScope(scope); 00447 scope+="::"+pd->name(); 00448 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope); 00449 if (d) 00450 { 00451 pd->setPageScope(d); 00452 } 00453 } 00454 } 00455 00456 static void addRelatedPage(EntryNav *rootNav) 00457 { 00458 Entry *root = rootNav->entry(); 00459 GroupDef *gd=0; 00460 QListIterator<Grouping> gli(*root->groups); 00461 Grouping *g; 00462 for (;(g=gli.current());++gli) 00463 { 00464 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break; 00465 } 00466 //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd); 00467 QCString doc; 00468 if (root->brief.isEmpty()) 00469 { 00470 doc=root->doc; 00471 } 00472 else 00473 { 00474 doc=root->brief+"\n\n"+root->doc; 00475 } 00476 PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors, 00477 root->fileName,root->startLine, 00478 root->sli, 00479 gd,rootNav->tagInfo() 00480 ); 00481 if (pd) 00482 { 00483 pd->addSectionsToDefinition(root->anchors); 00484 addPageToContext(pd,rootNav); 00485 } 00486 } 00487 00488 static void buildGroupListFiltered(EntryNav *rootNav,bool additional) 00489 { 00490 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty()) 00491 { 00492 //printf("Found group %s title=`%s type=%d'\n", 00493 // root->name.data(),root->type.data(),root->groupDocType); 00494 00495 rootNav->loadEntry(g_storage); 00496 Entry *root = rootNav->entry(); 00497 00498 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) || 00499 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional)) 00500 { 00501 GroupDef *gd; 00502 00503 if ((gd=Doxygen::groupSDict->find(root->name))) 00504 { 00505 #if 0 00506 if ( root->groupDocType==Entry::GROUPDOC_NORMAL ) 00507 { 00508 warn(root->fileName,root->startLine, 00509 "Warning: group %s already documented. " 00510 "Skipping documentation.", 00511 root->name.data()); 00512 } 00513 else 00514 #endif 00515 { 00516 if ( !gd->hasGroupTitle() ) 00517 gd->setGroupTitle( root->type ); 00518 else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type ) 00519 warn( root->fileName,root->startLine, 00520 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n", 00521 root->name.data(), root->type.data(), gd->groupTitle() ); 00522 //if ( gd->briefDescription().isEmpty() ) 00523 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 00524 //if ( !root->doc.stripWhiteSpace().isEmpty() ) 00525 gd->setDocumentation( root->doc, root->docFile, root->docLine ); 00526 gd->addSectionsToDefinition(root->anchors); 00527 gd->setRefItems(root->sli); 00528 //addGroupToGroups(root,gd); 00529 } 00530 } 00531 else 00532 { 00533 if (rootNav->tagInfo()) 00534 { 00535 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName); 00536 gd->setReference(rootNav->tagInfo()->tagName); 00537 } 00538 else 00539 { 00540 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type); 00541 } 00542 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 00543 gd->setDocumentation(root->doc,root->docFile,root->docLine); 00544 gd->addSectionsToDefinition(root->anchors); 00545 Doxygen::groupSDict->append(root->name,gd); 00546 gd->setRefItems(root->sli); 00547 } 00548 } 00549 00550 rootNav->releaseEntry(); 00551 } 00552 if (rootNav->children()) 00553 { 00554 EntryNavListIterator eli(*rootNav->children()); 00555 EntryNav *e; 00556 for (;(e=eli.current());++eli) 00557 { 00558 buildGroupListFiltered(e,additional); 00559 } 00560 } 00561 } 00562 00563 static void buildGroupList(EntryNav *rootNav) 00564 { 00565 // first process the @defgroups blocks 00566 buildGroupListFiltered(rootNav,FALSE); 00567 // then process the @addtogroup, @weakgroup blocks 00568 buildGroupListFiltered(rootNav,TRUE); 00569 } 00570 00571 static void findGroupScope(EntryNav *rootNav) 00572 { 00573 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && 00574 rootNav->parent() && !rootNav->parent()->name().isEmpty()) 00575 { 00576 GroupDef *gd; 00577 if ((gd=Doxygen::groupSDict->find(rootNav->name()))) 00578 { 00579 QCString scope = rootNav->parent()->name(); 00580 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC) 00581 { 00582 scope=substitute(scope,".","::"); 00583 } 00584 scope = stripAnonymousNamespaceScope(scope); 00585 scope+="::"+gd->name(); 00586 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope); 00587 if (d) 00588 { 00589 gd->setGroupScope(d); 00590 } 00591 } 00592 } 00593 RECURSE_ENTRYTREE(findGroupScope,rootNav); 00594 } 00595 00596 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional) 00597 { 00598 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty()) 00599 { 00600 rootNav->loadEntry(g_storage); 00601 Entry *root = rootNav->entry(); 00602 00603 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) || 00604 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional)) 00605 { 00606 GroupDef *gd; 00607 if ((gd=Doxygen::groupSDict->find(root->name))) 00608 { 00609 //printf("adding %s to group %s\n",root->name.data(),gd->name().data()); 00610 addGroupToGroups(root,gd); 00611 } 00612 } 00613 00614 rootNav->releaseEntry(); 00615 } 00616 if (rootNav->children()) 00617 { 00618 EntryNavListIterator eli(*rootNav->children()); 00619 EntryNav *e; 00620 for (;(e=eli.current());++eli) 00621 { 00622 organizeSubGroupsFiltered(e,additional); 00623 } 00624 } 00625 } 00626 00627 static void organizeSubGroups(EntryNav *rootNav) 00628 { 00629 //printf("Defining groups\n"); 00630 // first process the @defgroups blocks 00631 organizeSubGroupsFiltered(rootNav,FALSE); 00632 //printf("Additional groups\n"); 00633 // then process the @addtogroup, @weakgroup blocks 00634 organizeSubGroupsFiltered(rootNav,TRUE); 00635 } 00636 00637 //---------------------------------------------------------------------- 00638 00639 static void buildFileList(EntryNav *rootNav) 00640 { 00641 if (((rootNav->section()==Entry::FILEDOC_SEC) || 00642 ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) && 00643 !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files 00644 ) 00645 { 00646 rootNav->loadEntry(g_storage); 00647 Entry *root = rootNav->entry(); 00648 00649 bool ambig; 00650 FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig); 00651 //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd); 00652 if (fd && !ambig) 00653 { 00654 #if 0 00655 if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) || 00656 (!root->brief.isEmpty() && !fd->briefDescription().isEmpty())) 00657 { 00658 warn( 00659 root->fileName,root->startLine, 00660 "Warning: file %s already documented. " 00661 "Skipping documentation.", 00662 root->name.data() 00663 ); 00664 } 00665 else 00666 #endif 00667 { 00668 //printf("Adding documentation!\n"); 00669 // using FALSE in setDocumentation is small hack to make sure a file 00670 // is documented even if a \file command is used without further 00671 // documentation 00672 fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE); 00673 fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 00674 fd->addSectionsToDefinition(root->anchors); 00675 fd->setRefItems(root->sli); 00676 QListIterator<Grouping> gli(*root->groups); 00677 Grouping *g; 00678 for (;(g=gli.current());++gli) 00679 { 00680 GroupDef *gd=0; 00681 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) 00682 { 00683 gd->addFile(fd); 00684 //printf("File %s: in group %s\n",fd->name().data(),s->data()); 00685 } 00686 } 00687 } 00688 } 00689 else 00690 { 00691 const char *fn = root->fileName.data(); 00692 QCString text; 00693 text.sprintf("Warning: the name `%s' supplied as " 00694 "the second argument in the \\file statement ", 00695 root->name.data() 00696 ); 00697 if (ambig) // name is ambigious 00698 { 00699 text+="matches the following input files:\n"; 00700 text+=showFileDefMatches(Doxygen::inputNameDict,root->name); 00701 text+="Please use a more specific name by " 00702 "including a (larger) part of the path!"; 00703 } 00704 else // name is not an input file 00705 { 00706 text+="is not an input file"; 00707 } 00708 warn(fn,root->startLine,text); 00709 } 00710 00711 rootNav->releaseEntry(); 00712 } 00713 RECURSE_ENTRYTREE(buildFileList,rootNav); 00714 } 00715 00716 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root) 00717 { 00718 if ( 00719 (!root->doc.stripWhiteSpace().isEmpty() || 00720 !root->brief.stripWhiteSpace().isEmpty() || 00721 Config_getBool("EXTRACT_ALL") 00722 ) && root->protection!=Private 00723 ) 00724 { 00725 //printf(">>>>>> includeFile=%s\n",root->includeFile.data()); 00726 00727 bool ambig; 00728 FileDef *fd=0; 00729 // see if we need to include a verbatim copy of the header file 00730 //printf("root->includeFile=%s\n",root->includeFile.data()); 00731 if (!root->includeFile.isEmpty() && 00732 (fd=findFileDef(Doxygen::inputNameDict,root->includeFile,ambig))==0 00733 ) 00734 { // explicit request 00735 QCString text; 00736 text.sprintf("Warning: the name `%s' supplied as " 00737 "the argument of the \\class, \\struct, \\union, or \\include command ", 00738 root->includeFile.data() 00739 ); 00740 if (ambig) // name is ambigious 00741 { 00742 text+="matches the following input files:\n"; 00743 text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile); 00744 text+="Please use a more specific name by " 00745 "including a (larger) part of the path!"; 00746 } 00747 else // name is not an input file 00748 { 00749 text+="is not an input file"; 00750 } 00751 warn(root->fileName,root->startLine,text); 00752 } 00753 else if (root->includeFile.isEmpty() && ifd && 00754 // see if the file extension makes sense 00755 guessSection(ifd->name())==Entry::HEADER_SEC) 00756 { // implicit assumption 00757 fd=ifd; 00758 } 00759 00760 // if a file is found, we mark it as a source file. 00761 if (fd) 00762 { 00763 QCString iName = !root->includeName.isEmpty() ? 00764 root->includeName.data() : root->includeFile.data(); 00765 bool local=FALSE; 00766 if (!iName.isEmpty()) // user specified include file 00767 { 00768 local = iName.at(0)=='"'; // is it a local include file 00769 if (local || iName.at(0)=='<') 00770 { 00771 iName=iName.mid(1,iName.length()-2); // strip quotes or brackets 00772 } 00773 } 00774 else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) 00775 { 00776 iName=stripFromIncludePath(fd->absFilePath()); 00777 } 00778 else // use name of the file containing the class definition 00779 { 00780 iName=fd->name(); 00781 } 00782 if (fd->generateSourceFile()) // generate code for header 00783 { 00784 cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty()); 00785 } 00786 else // put #include in the class documentation without link 00787 { 00788 cd->setIncludeFile(0,iName,local,TRUE); 00789 } 00790 } 00791 } 00792 } 00793 00794 #if 0 00795 static bool addNamespace(Entry *root,ClassDef *cd) 00796 { 00797 // see if this class is defined inside a namespace 00798 if (root->section & Entry::COMPOUND_MASK) 00799 { 00800 Entry *e = root->parent; 00801 while (e) 00802 { 00803 if (e->section==Entry::NAMESPACE_SEC) 00804 { 00805 NamespaceDef *nd=0; 00806 QCString nsName = stripAnonymousNamespaceScope(e->name); 00807 //printf("addNameSpace() trying: %s\n",nsName.data()); 00808 if (!nsName.isEmpty() && nsName.at(0)!='@' && 00809 (nd=getResolvedNamespace(nsName)) 00810 ) 00811 { 00812 cd->setNamespace(nd); 00813 cd->setOuterScope(nd); 00814 nd->insertClass(cd); 00815 return TRUE; 00816 } 00817 } 00818 e=e->parent; 00819 } 00820 } 00821 return FALSE; 00822 } 00823 #endif 00824 00825 #if 0 00826 static Definition *findScope(Entry *root,int level=0) 00827 { 00828 if (root==0) return 0; 00829 //printf("start findScope name=%s\n",root->name.data()); 00830 Definition *result=0; 00831 if (root->section&Entry::SCOPE_MASK) 00832 { 00833 result = findScope(root->parent,level+1); // traverse to the root of the tree 00834 if (result) 00835 { 00836 //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level); 00837 // TODO: look at template arguments 00838 result = result->findInnerCompound(root->name); 00839 } 00840 else // reached the global scope 00841 { 00842 // TODO: look at template arguments 00843 result = Doxygen::globalScope->findInnerCompound(root->name); 00844 //printf("Found in globalScope %s at level %d\n",result->name().data(),level); 00845 } 00846 } 00847 //printf("end findScope(%s,%d)=%s\n",root->name.data(), 00848 // level,result==0 ? "<none>" : result->name().data()); 00849 return result; 00850 } 00851 #endif 00852 00857 static Definition *buildScopeFromQualifiedName(const QCString name,int level) 00858 { 00859 int i=0; 00860 int p=0,l; 00861 Definition *prevScope=Doxygen::globalScope; 00862 QCString fullScope; 00863 while (i<level) 00864 { 00865 int idx=getScopeFragment(name,p,&l); 00866 QCString nsName = name.mid(idx,l); 00867 if (nsName.isEmpty()) return prevScope; 00868 if (!fullScope.isEmpty()) fullScope+="::"; 00869 fullScope+=nsName; 00870 NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope); 00871 Definition *innerScope = nd; 00872 ClassDef *cd=0; 00873 if (nd==0) cd = getClass(fullScope); 00874 if (nd==0 && cd) // scope is a class 00875 { 00876 innerScope = cd; 00877 } 00878 else if (nd==0 && cd==0) // scope is not known! 00879 { 00880 // introduce bogus namespace 00881 //printf("adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data()); 00882 nd=new NamespaceDef( 00883 "[generated]",1,fullScope); 00884 00885 // add namespace to the list 00886 Doxygen::namespaceSDict->inSort(fullScope,nd); 00887 innerScope = nd; 00888 } 00889 else // scope is a namespace 00890 { 00891 } 00892 // make the parent/child scope relation 00893 prevScope->addInnerCompound(innerScope); 00894 innerScope->setOuterScope(prevScope); 00895 // proceed to the next scope fragment 00896 p=idx+l+2; 00897 prevScope=innerScope; 00898 i++; 00899 } 00900 return prevScope; 00901 } 00902 00903 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n, 00904 FileDef *fileScope) 00905 { 00906 //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data()); 00907 Definition *resultScope=startScope; 00908 if (resultScope==0) resultScope=Doxygen::globalScope; 00909 QCString scope=stripTemplateSpecifiersFromScope(n,FALSE); 00910 int l1=0,i1; 00911 i1=getScopeFragment(scope,0,&l1); 00912 if (i1==-1) 00913 { 00914 //printf(">no fragments!\n"); 00915 return resultScope; 00916 } 00917 int p=i1+l1,l2=0,i2; 00918 while ((i2=getScopeFragment(scope,p,&l2))!=-1) 00919 { 00920 QCString nestedNameSpecifier = scope.mid(i1,l1); 00921 Definition *orgScope = resultScope; 00922 //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data()); 00923 resultScope = resultScope->findInnerCompound(nestedNameSpecifier); 00924 //printf(" resultScope=%p\n",resultScope); 00925 if (resultScope==0) 00926 { 00927 NamespaceSDict *usedNamespaces; 00928 if (orgScope==Doxygen::globalScope && fileScope && 00929 (usedNamespaces = fileScope->getUsedNamespaces())) 00930 // also search for used namespaces 00931 { 00932 NamespaceSDict::Iterator ni(*usedNamespaces); 00933 NamespaceDef *nd; 00934 for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni) 00935 { 00936 // restart search within the used namespace 00937 resultScope = findScopeFromQualifiedName(nd,n,fileScope); 00938 } 00939 if (resultScope) 00940 { 00941 // for a nested class A::I in used namespace N, we get 00942 // N::A::I while looking for A, so we should compare 00943 // resultScope->name() against scope.left(i2+l2) 00944 //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data()); 00945 if (rightScopeMatch(resultScope->name(),scope.left(i2+l2))) 00946 { 00947 break; 00948 } 00949 goto nextFragment; 00950 } 00951 } 00952 00953 // also search for used classes. Complication: we haven't been able 00954 // to put them in the right scope yet, because we are still resolving 00955 // the scope relations! 00956 // Therefore loop through all used classes and see if there is a right 00957 // scope match between the used class and nestedNameSpecifier. 00958 QDictIterator<FileDef> ui(g_usingDeclarations); 00959 FileDef *usedFd; 00960 for (ui.toFirst();(usedFd=ui.current());++ui) 00961 { 00962 //printf("Checking using class %s\n",ui.currentKey()); 00963 if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier)) 00964 { 00965 // ui.currentKey() is the fully qualified name of nestedNameSpecifier 00966 // so use this instead. 00967 QCString fqn = QCString(ui.currentKey())+ 00968 scope.right(scope.length()-p); 00969 resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::")); 00970 //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope); 00971 if (resultScope) 00972 { 00973 //printf("> Match! resultScope=%s\n",resultScope->name().data()); 00974 return resultScope; 00975 } 00976 } 00977 } 00978 00979 //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data()); 00980 return 0; 00981 } 00982 nextFragment: 00983 i1=i2; 00984 l1=l2; 00985 p=i2+l2; 00986 } 00987 //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data()); 00988 return resultScope; 00989 } 00990 00991 ArgumentList *getTemplateArgumentsFromName( 00992 const QCString &name, 00993 const QList<ArgumentList> *tArgLists) 00994 { 00995 if (tArgLists==0) return 0; 00996 00997 QListIterator<ArgumentList> ali(*tArgLists); 00998 // for each scope fragment, check if it is a template and advance through 00999 // the list if so. 01000 int i,p=0; 01001 while ((i=name.find("::",p))!=-1) 01002 { 01003 NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i)); 01004 if (nd==0) 01005 { 01006 ClassDef *cd = getClass(name.left(i)); 01007 if (cd) 01008 { 01009 if (cd->templateArguments()) 01010 { 01011 ++ali; 01012 } 01013 } 01014 } 01015 p=i+2; 01016 } 01017 return ali.current(); 01018 } 01019 01020 static ClassDef::CompoundType convertToCompoundType(int section,int specifier) 01021 { 01022 ClassDef::CompoundType sec=ClassDef::Class; 01023 if (specifier&Entry::Struct) 01024 sec=ClassDef::Struct; 01025 else if (specifier&Entry::Union) 01026 sec=ClassDef::Union; 01027 else if (specifier&Entry::Interface) 01028 sec=ClassDef::Interface; 01029 else if (specifier&Entry::Protocol) 01030 sec=ClassDef::Protocol; 01031 else if (specifier&Entry::Category) 01032 sec=ClassDef::Category; 01033 else if (specifier&Entry::Exception) 01034 sec=ClassDef::Exception; 01035 01036 switch(section) 01037 { 01038 //case Entry::UNION_SEC: 01039 case Entry::UNIONDOC_SEC: 01040 sec=ClassDef::Union; 01041 break; 01042 //case Entry::STRUCT_SEC: 01043 case Entry::STRUCTDOC_SEC: 01044 sec=ClassDef::Struct; 01045 break; 01046 //case Entry::INTERFACE_SEC: 01047 case Entry::INTERFACEDOC_SEC: 01048 sec=ClassDef::Interface; 01049 break; 01050 //case Entry::PROTOCOL_SEC: 01051 case Entry::PROTOCOLDOC_SEC: 01052 sec=ClassDef::Protocol; 01053 break; 01054 //case Entry::CATEGORY_SEC: 01055 case Entry::CATEGORYDOC_SEC: 01056 sec=ClassDef::Category; 01057 break; 01058 //case Entry::EXCEPTION_SEC: 01059 case Entry::EXCEPTIONDOC_SEC: 01060 sec=ClassDef::Exception; 01061 break; 01062 } 01063 return sec; 01064 } 01065 01066 01067 static void addClassToContext(EntryNav *rootNav) 01068 { 01069 //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data()); 01070 rootNav->loadEntry(g_storage); 01071 Entry *root = rootNav->entry(); 01072 01073 //NamespaceDef *nd = 0; 01074 FileDef *fd = rootNav->fileDef(); 01075 01076 QCString scName; 01077 if (rootNav->parent()->section()&Entry::SCOPE_MASK) 01078 { 01079 scName=rootNav->parent()->name(); 01080 } 01081 // name without parent's scope: TODO: is this still true? 01082 QCString fullName = root->name; 01083 01084 // strip off any template parameters (but not those for specializations) 01085 fullName=stripTemplateSpecifiersFromScope(fullName); 01086 01087 // name with scope 01088 QCString qualifiedName = fullName; 01089 if (!scName.isEmpty() && !leftScopeMatch(fullName,scName)) 01090 { 01091 qualifiedName.prepend(scName+"::"); 01092 } 01093 01094 ClassDef *cd = getClass(qualifiedName); 01095 01096 Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n", 01097 cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd); 01098 01099 if (cd) 01100 { 01101 fullName=cd->name(); 01102 Debug::print(Debug::Classes,0," Existing class %s!\n",cd->name().data()); 01103 //if (cd->templateArguments()==0) 01104 //{ 01105 // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data()); 01106 // cd->setTemplateArguments(tArgList); 01107 //} 01108 #if 0 01109 if (!root->doc.isEmpty() || !root->brief.isEmpty() || 01110 (root->bodyLine!=-1 && Config_getBool("SOURCE_BROWSER")) 01111 ) 01112 // block contains something that ends up in the docs 01113 { 01114 if (!root->doc.isEmpty() && !cd->documentation().isEmpty()) 01115 { 01116 warn( 01117 root->fileName,root->startLine, 01118 "Warning: class %s already has a detailed description found in file %s at line %d. " 01119 "Skipping the one found here.", 01120 fullName.data(),cd->docFile().data(),cd->docLine() 01121 ); 01122 } 01123 else if (!root->doc.isEmpty()) 01124 #endif 01125 { 01126 cd->setDocumentation(root->doc,root->docFile,root->docLine); 01127 } 01128 #if 0 01129 if (!root->brief.isEmpty() && !cd->briefDescription().isEmpty()) 01130 { 01131 warn( 01132 root->fileName,root->startLine, 01133 "Warning: class %s already has a brief description found in file %s at line %d\n" 01134 " skipping the one found here.", 01135 fullName.data(),cd->briefFile().data(),cd->briefLine() 01136 ); 01137 } 01138 else if (!root->brief.isEmpty()) 01139 #endif 01140 { 01141 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01142 } 01143 if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1) 01144 { 01145 cd->setBodySegment(root->bodyLine,root->endBodyLine); 01146 cd->setBodyDef(fd); 01147 } 01148 //cd->setName(fullName); // change name to match docs 01149 #if 0 01150 } 01151 #endif 01152 01153 if (cd->templateArguments()==0) 01154 { 01155 // this happens if a template class declared with @class is found 01156 // before the actual definition. 01157 ArgumentList *tArgList = 01158 getTemplateArgumentsFromName(cd->name(),root->tArgLists); 01159 cd->setTemplateArguments(tArgList); 01160 } 01161 01162 cd->setCompoundType(convertToCompoundType(root->section,root->spec)); 01163 } 01164 else // new class 01165 { 01166 ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec); 01167 01168 QCString className; 01169 QCString namespaceName; 01170 extractNamespaceName(fullName,className,namespaceName); 01171 01172 //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n", 01173 // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data()); 01174 01175 QCString tagName; 01176 QCString refFileName; 01177 if (rootNav->tagInfo()) 01178 { 01179 tagName = rootNav->tagInfo()->tagName; 01180 refFileName = rootNav->tagInfo()->fileName; 01181 } 01182 cd=new ClassDef(root->fileName,root->startLine,fullName,sec, 01183 tagName,refFileName); 01184 Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d cd=%p\n", 01185 fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1,cd); 01186 cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition 01187 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01188 cd->setIsObjectiveC(root->objc); 01189 cd->setHidden(root->hidden); 01190 cd->setArtificial(root->artificial); 01191 cd->setTypeConstraints(root->typeConstr); 01192 //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data()); 01193 01194 ArgumentList *tArgList = 01195 getTemplateArgumentsFromName(fullName,root->tArgLists); 01196 //printf("class %s template args=%s\n",fullName.data(), 01197 // tArgList ? tempArgListToString(tArgList).data() : "<none>"); 01198 cd->setTemplateArguments(tArgList); 01199 cd->setProtection(root->protection); 01200 cd->setIsStatic(root->stat); 01201 01202 // file definition containing the class cd 01203 cd->setBodySegment(root->bodyLine,root->endBodyLine); 01204 cd->setBodyDef(fd); 01205 01206 // see if the class is found inside a namespace 01207 //bool found=addNamespace(root,cd); 01208 01209 01210 // the empty string test is needed for extract all case 01211 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01212 cd->insertUsedFile(root->fileName); 01213 01214 // add class to the list 01215 //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data()); 01216 Doxygen::classSDict->append(fullName,cd); 01217 01218 } 01219 01220 cd->addSectionsToDefinition(root->anchors); 01221 if (!root->subGrouping) cd->setSubGrouping(FALSE); 01222 if (cd->hasDocumentation()) 01223 { 01224 addIncludeFile(cd,fd,root); 01225 } 01226 if (fd && (root->section & Entry::COMPOUND_MASK)) 01227 { 01228 //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n", 01229 // cd->name().data(), 01230 // fd->name().data(), 01231 // root->fileName.data() 01232 // ); 01233 cd->setFileDef(fd); 01234 fd->insertClass(cd); 01235 } 01236 addClassToGroups(root,cd); 01237 cd->setRefItems(root->sli); 01238 01239 rootNav->releaseEntry(); 01240 } 01241 01242 //---------------------------------------------------------------------- 01243 // build a list of all classes mentioned in the documentation 01244 // and all classes that have a documentation block before their definition. 01245 static void buildClassList(EntryNav *rootNav) 01246 { 01247 if ( 01248 ((rootNav->section() & Entry::COMPOUND_MASK) || 01249 rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty() 01250 ) 01251 { 01252 addClassToContext(rootNav); 01253 } 01254 RECURSE_ENTRYTREE(buildClassList,rootNav); 01255 } 01256 01257 static void buildClassDocList(EntryNav *rootNav) 01258 { 01259 if ( 01260 (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty() 01261 ) 01262 { 01263 addClassToContext(rootNav); 01264 } 01265 RECURSE_ENTRYTREE(buildClassDocList,rootNav); 01266 } 01267 01268 static void resolveClassNestingRelations() 01269 { 01270 ClassSDict::Iterator cli(*Doxygen::classSDict); 01271 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; 01272 01273 bool done=FALSE; 01274 int iteration=0; 01275 while (!done) 01276 { 01277 done=TRUE; 01278 ++iteration; 01279 ClassDef *cd=0; 01280 for (cli.toFirst();(cd=cli.current());++cli) 01281 { 01282 if (!cd->visited) 01283 { 01284 QCString name = stripAnonymousNamespaceScope(cd->name()); 01285 //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration); 01286 // also add class to the correct structural context 01287 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope, 01288 name,cd->getFileDef()); 01289 if (d) 01290 { 01291 //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration); 01292 d->addInnerCompound(cd); 01293 cd->setOuterScope(d); 01294 cd->visited=TRUE; 01295 done=FALSE; 01296 } 01297 //else 01298 //{ 01299 // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration); 01300 //} 01301 } 01302 } 01303 } 01304 01305 //give warnings for unresolved compounds 01306 ClassDef *cd=0; 01307 for (cli.toFirst();(cd=cli.current());++cli) 01308 { 01309 if (!cd->visited) 01310 { 01311 QCString name = stripAnonymousNamespaceScope(cd->name()); 01312 //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration); 01314 // anyway, so we can at least relate scopes properly. 01315 Definition *d = buildScopeFromQualifiedName(name,name.contains("::")); 01316 if (d!=cd) // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; } 01317 // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found! 01318 { 01319 d->addInnerCompound(cd); 01320 cd->setOuterScope(d); 01321 warn(cd->getDefFileName(),cd->getDefLine(), 01322 "Warning: Internal inconsistency: scope for class %s not " 01323 "found!",name.data() 01324 ); 01325 } 01326 } 01327 } 01328 } 01329 01330 01331 //---------------------------------------------------------------------- 01332 // build a list of all namespaces mentioned in the documentation 01333 // and all namespaces that have a documentation block before their definition. 01334 static void buildNamespaceList(EntryNav *rootNav) 01335 { 01336 if ( 01337 (rootNav->section()==Entry::NAMESPACE_SEC || 01338 rootNav->section()==Entry::NAMESPACEDOC_SEC || 01339 rootNav->section()==Entry::PACKAGEDOC_SEC 01340 ) && 01341 !rootNav->name().isEmpty() 01342 ) 01343 { 01344 rootNav->loadEntry(g_storage); 01345 Entry *root = rootNav->entry(); 01346 01347 //printf("** buildNamespaceList(%s)\n",root->name.data()); 01348 01349 QCString fName = root->name; 01350 if (root->section==Entry::PACKAGEDOC_SEC) 01351 { 01352 fName=substitute(fName,".","::"); 01353 } 01354 01355 QCString fullName = stripAnonymousNamespaceScope(fName); 01356 if (!fullName.isEmpty()) 01357 { 01358 //printf("Found namespace %s in %s at line %d\n",root->name.data(), 01359 // root->fileName.data(), root->startLine); 01360 NamespaceDef *nd; 01361 if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace 01362 { 01363 #if 0 01364 if (!root->doc.isEmpty() || !root->brief.isEmpty()) // block contains docs 01365 { 01366 if (nd->documentation().isEmpty() && !root->doc.isEmpty()) 01367 { 01368 #endif 01369 nd->setDocumentation(root->doc,root->docFile,root->docLine); 01370 nd->setName(fullName); // change name to match docs 01371 nd->addSectionsToDefinition(root->anchors); 01372 #if 0 01373 } 01374 else if (!nd->documentation().isEmpty() && !root->doc.isEmpty()) 01375 { 01376 warn( 01377 root->fileName,root->startLine, 01378 "Warning: namespace %s already has a detailed description found in file %s at line %d. " 01379 "Skipping the documentation found here.", 01380 fullName.data(),nd->docFile().data(),nd->docLine()); 01381 } 01382 if (nd->briefDescription().isEmpty() && !root->brief.isEmpty()) 01383 { 01384 #endif 01385 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01386 #if 0 01387 nd->setName(fullName); // change name to match docs 01388 } 01389 else if (!nd->briefDescription().isEmpty() && !root->brief.isEmpty()) 01390 { 01391 warn(root->fileName,root->startLine, 01392 "Warning: namespace %s already has a brief description found in file %s at line %d. " 01393 "Skipping the documentation found here.", 01394 fullName.data(),nd->docFile().data(),nd->docLine() 01395 ); 01396 } 01397 } 01398 #endif 01399 01400 // file definition containing the namespace nd 01401 FileDef *fd=rootNav->fileDef(); 01402 // insert the namespace in the file definition 01403 if (fd) fd->insertNamespace(nd); 01404 addNamespaceToGroups(root,nd); 01405 nd->setRefItems(root->sli); 01406 } 01407 else // fresh namespace 01408 { 01409 QCString tagName; 01410 QCString tagFileName; 01411 if (rootNav->tagInfo()) 01412 { 01413 tagName=rootNav->tagInfo()->tagName; 01414 tagFileName=rootNav->tagInfo()->fileName; 01415 } 01416 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName); 01417 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition 01418 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01419 nd->addSectionsToDefinition(root->anchors); 01420 nd->setHidden(root->hidden); 01421 nd->setArtificial(root->artificial); 01422 01423 //printf("Adding namespace to group\n"); 01424 addNamespaceToGroups(root,nd); 01425 nd->setRefItems(root->sli); 01426 01427 // file definition containing the namespace nd 01428 FileDef *fd=rootNav->fileDef(); 01429 // insert the namespace in the file definition 01430 if (fd) fd->insertNamespace(nd); 01431 01432 // the empty string test is needed for extract all case 01433 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01434 nd->insertUsedFile(root->fileName); 01435 nd->setBodySegment(root->bodyLine,root->endBodyLine); 01436 nd->setBodyDef(fd); 01437 // add class to the list 01438 Doxygen::namespaceSDict->inSort(fullName,nd); 01439 01440 // also add namespace to the correct structural context 01441 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName); 01442 //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>"); 01443 if (d==0) // we didn't find anything, create the scope artificially 01444 // anyway, so we can at least relate scopes properly. 01445 { 01446 Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::")); 01447 d->addInnerCompound(nd); 01448 nd->setOuterScope(d); 01449 // TODO: Due to the order in which the tag file is written 01450 // a nested class can be found before its parent! 01451 } 01452 else 01453 { 01454 d->addInnerCompound(nd); 01455 nd->setOuterScope(d); 01456 } 01457 } 01458 } 01459 01460 rootNav->releaseEntry(); 01461 } 01462 RECURSE_ENTRYTREE(buildNamespaceList,rootNav); 01463 } 01464 01465 //---------------------------------------------------------------------- 01466 01467 static NamespaceDef *findUsedNamespace(const NamespaceSDict *unl, 01468 const QCString &name) 01469 { 01470 NamespaceDef *usingNd =0; 01471 if (unl) 01472 { 01473 //printf("Found namespace dict %d\n",unl->count()); 01474 NamespaceSDict::Iterator unli(*unl); 01475 NamespaceDef *und; 01476 for (unli.toFirst();(und=unli.current());++unli) 01477 { 01478 QCString uScope=und->name()+"::"; 01479 usingNd = getResolvedNamespace(uScope+name); 01480 //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd); 01481 } 01482 } 01483 return usingNd; 01484 } 01485 01486 static void findUsingDirectives(EntryNav *rootNav) 01487 { 01488 if (rootNav->section()==Entry::USINGDIR_SEC) 01489 { 01490 rootNav->loadEntry(g_storage); 01491 Entry *root = rootNav->entry(); 01492 01493 //printf("Found using directive %s at line %d of %s\n", 01494 // root->name.data(),root->startLine,root->fileName.data()); 01495 QCString name=substitute(root->name,".","::"); 01496 if (!name.isEmpty()) 01497 { 01498 NamespaceDef *usingNd = 0; 01499 NamespaceDef *nd = 0; 01500 FileDef *fd = rootNav->fileDef(); 01501 QCString nsName; 01502 01503 // see if the using statement was found inside a namespace or inside 01504 // the global file scope. 01505 if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC && 01506 (fd==0 || !fd->isJava()) // not a .java file 01507 ) 01508 { 01509 nsName=stripAnonymousNamespaceScope(rootNav->parent()->name()); 01510 if (!nsName.isEmpty()) 01511 { 01512 nd = getResolvedNamespace(nsName); 01513 } 01514 } 01515 01516 // find the scope in which the `using' namespace is defined by prepending 01517 // the possible scopes in which the using statement was found, starting 01518 // with the most inner scope and going to the most outer scope (i.e. 01519 // file scope). 01520 int scopeOffset = nsName.length(); 01521 do 01522 { 01523 QCString scope=scopeOffset>0 ? 01524 nsName.left(scopeOffset)+"::" : QCString(); 01525 usingNd = getResolvedNamespace(scope+name); 01526 //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd); 01527 if (scopeOffset==0) 01528 { 01529 scopeOffset=-1; 01530 } 01531 else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1) 01532 { 01533 scopeOffset=0; 01534 } 01535 } while (scopeOffset>=0 && usingNd==0); 01536 01537 if (usingNd==0 && nd) // not found, try used namespaces in this scope 01538 // or in one of the parent namespace scopes 01539 { 01540 NamespaceDef *pnd = nd; 01541 while (pnd && usingNd==0) 01542 { 01543 // also try with one of the used namespaces found earlier 01544 usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name); 01545 01546 // goto the parent 01547 Definition *s = pnd->getOuterScope(); 01548 if (s && s->definitionType()==Definition::TypeNamespace) 01549 { 01550 pnd = (NamespaceDef*)s; 01551 } 01552 else 01553 { 01554 pnd = 0; 01555 } 01556 } 01557 } 01558 if (usingNd==0 && fd) // still nothing, also try used namespace in the 01559 // global scope 01560 { 01561 usingNd = findUsedNamespace(fd->getUsedNamespaces(),name); 01562 } 01563 01564 //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>"); 01565 01566 // add the namespace the correct scope 01567 if (usingNd) 01568 { 01569 //printf("using fd=%p nd=%p\n",fd,nd); 01570 if (nd) 01571 { 01572 //printf("Inside namespace %s\n",nd->name().data()); 01573 nd->addUsingDirective(usingNd); 01574 } 01575 else if (fd) 01576 { 01577 //printf("Inside file %s\n",fd->name().data()); 01578 fd->addUsingDirective(usingNd); 01579 } 01580 } 01581 else // unknown namespace, but add it anyway. 01582 { 01583 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name); 01584 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition 01585 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01586 nd->addSectionsToDefinition(root->anchors); 01587 //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden); 01588 nd->setHidden(root->hidden); 01589 nd->setArtificial(TRUE); 01590 01591 QListIterator<Grouping> gli(*root->groups); 01592 Grouping *g; 01593 for (;(g=gli.current());++gli) 01594 { 01595 GroupDef *gd=0; 01596 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) 01597 gd->addNamespace(nd); 01598 } 01599 01600 // insert the namespace in the file definition 01601 if (fd) 01602 { 01603 fd->insertNamespace(nd); 01604 fd->addUsingDirective(nd); 01605 } 01606 01607 // the empty string test is needed for extract all case 01608 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01609 nd->insertUsedFile(root->fileName); 01610 // add class to the list 01611 Doxygen::namespaceSDict->inSort(name,nd); 01612 nd->setRefItems(root->sli); 01613 } 01614 } 01615 01616 rootNav->releaseEntry(); 01617 } 01618 RECURSE_ENTRYTREE(findUsingDirectives,rootNav); 01619 } 01620 01621 //---------------------------------------------------------------------- 01622 01623 static void buildListOfUsingDecls(EntryNav *rootNav) 01624 { 01625 if (rootNav->section()==Entry::USINGDECL_SEC && 01626 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member 01627 ) 01628 { 01629 rootNav->loadEntry(g_storage); 01630 Entry *root = rootNav->entry(); 01631 01632 QCString name = substitute(root->name,".","::"); 01633 if (g_usingDeclarations.find(name)==0) 01634 { 01635 FileDef *fd = rootNav->fileDef(); 01636 if (fd) 01637 { 01638 g_usingDeclarations.insert(name,fd); 01639 } 01640 } 01641 01642 rootNav->releaseEntry(); 01643 } 01644 RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav); 01645 } 01646 01647 01648 static void findUsingDeclarations(EntryNav *rootNav) 01649 { 01650 if (rootNav->section()==Entry::USINGDECL_SEC && 01651 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member 01652 ) 01653 { 01654 rootNav->loadEntry(g_storage); 01655 Entry *root = rootNav->entry(); 01656 01657 //printf("Found using declaration %s at line %d of %s inside section %x\n", 01658 // root->name.data(),root->startLine,root->fileName.data(), 01659 // root->parent->section); 01660 if (!root->name.isEmpty()) 01661 { 01662 ClassDef *usingCd = 0; 01663 NamespaceDef *nd = 0; 01664 FileDef *fd = rootNav->fileDef(); 01665 QCString scName; 01666 01667 // see if the using statement was found inside a namespace or inside 01668 // the global file scope. 01669 if (rootNav->parent()->section() == Entry::NAMESPACE_SEC) 01670 { 01671 scName=rootNav->parent()->name(); 01672 if (!scName.isEmpty()) 01673 { 01674 nd = getResolvedNamespace(scName); 01675 } 01676 } 01677 01678 // Assume the using statement was used to import a class. 01679 // Find the scope in which the `using' namespace is defined by prepending 01680 // the possible scopes in which the using statement was found, starting 01681 // with the most inner scope and going to the most outer scope (i.e. 01682 // file scope). 01683 01684 QCString name = substitute(root->name,".","::"); 01685 //MemberDef *mtd=0; 01686 //usingCd = getResolvedClass(nd,fd,name,&mtd); 01687 usingCd = getClass(name); 01688 if (usingCd==0) 01689 { 01690 usingCd = Doxygen::hiddenClasses->find(name); 01691 } 01692 01693 //printf("%s -> %p\n",root->name.data(),usingCd); 01694 if (usingCd==0) // definition not in the input => add an artificial class 01695 { 01696 Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n", 01697 name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1); 01698 usingCd = new ClassDef( 01699 "<using>",1, 01700 name,ClassDef::Class); 01701 Doxygen::hiddenClasses->append(root->name,usingCd); 01702 usingCd->setArtificial(TRUE); 01703 } 01704 else 01705 { 01706 Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n", 01707 usingCd->name().data(),nd?nd->name().data():fd->name().data()); 01708 } 01709 01710 #if 0 01711 if (mtd) // add the typedef to the correct scope 01712 { 01713 if (nd) 01714 { 01715 //printf("Inside namespace %s\n",nd->name().data()); 01716 nd->addUsingDeclaration(mtd); 01717 } 01718 else if (fd) 01719 { 01720 //printf("Inside file %s\n",nd->name().data()); 01721 fd->addUsingDeclaration(mtd); 01722 } 01723 } 01724 else 01725 #endif 01726 if (usingCd) // add the class to the correct scope 01727 { 01728 if (nd) 01729 { 01730 //printf("Inside namespace %s\n",nd->name().data()); 01731 nd->addUsingDeclaration(usingCd); 01732 } 01733 else if (fd) 01734 { 01735 //printf("Inside file %s\n",nd->name().data()); 01736 fd->addUsingDeclaration(usingCd); 01737 } 01738 } 01739 } 01740 01741 rootNav->releaseEntry(); 01742 } 01743 RECURSE_ENTRYTREE(findUsingDeclarations,rootNav); 01744 } 01745 01746 //---------------------------------------------------------------------- 01747 01748 static void findUsingDeclImports(EntryNav *rootNav) 01749 { 01750 if (rootNav->section()==Entry::USINGDECL_SEC && 01751 (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member 01752 ) 01753 { 01754 //printf("Found using declaration %s at line %d of %s inside section %x\n", 01755 // root->name.data(),root->startLine,root->fileName.data(), 01756 // root->parent->section); 01757 QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name()); 01758 fullName=stripAnonymousNamespaceScope(fullName); 01759 fullName=stripTemplateSpecifiersFromScope(fullName); 01760 ClassDef *cd = getClass(fullName); 01761 if (cd) 01762 { 01763 //printf("found class %s\n",cd->name().data()); 01764 int i=rootNav->name().find("::"); 01765 if (i!=-1) 01766 { 01767 QCString scope=rootNav->name().left(i); 01768 QCString memName=rootNav->name().right(rootNav->name().length()-i-2); 01769 ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter 01770 if (bcd) 01771 { 01772 //printf("found class %s\n",bcd->name().data()); 01773 MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict(); 01774 if (mndict) 01775 { 01776 MemberNameInfo *mni = mndict->find(memName); 01777 if (mni) 01778 { 01779 MemberNameInfoIterator mnii(*mni); 01780 MemberInfo *mi; 01781 for ( ; (mi=mnii.current()) ; ++mnii ) 01782 { 01783 MemberDef *md = mi->memberDef; 01784 if (md && md->protection()!=Private) 01785 { 01786 01787 rootNav->loadEntry(g_storage); 01788 Entry *root = rootNav->entry(); 01789 01790 //printf("found member %s\n",mni->memberName()); 01791 MemberDef *newMd = 0; 01792 { 01793 LockingPtr<ArgumentList> templAl = md->templateArguments(); 01794 LockingPtr<ArgumentList> al = md->templateArguments(); 01795 newMd = new MemberDef( 01796 root->fileName,root->startLine, 01797 md->typeString(),memName,md->argsString(), 01798 md->excpString(),root->protection,root->virt, 01799 md->isStatic(),FALSE,md->memberType(), 01800 templAl.pointer(),al.pointer() 01801 ); 01802 } 01803 newMd->setMemberClass(cd); 01804 cd->insertMember(newMd); 01805 if (!root->doc.isEmpty() || !root->brief.isEmpty()) 01806 { 01807 newMd->setDocumentation(root->doc,root->docFile,root->docLine); 01808 newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01809 newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 01810 } 01811 else 01812 { 01813 newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine()); 01814 newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine()); 01815 newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine()); 01816 } 01817 newMd->setDefinition(md->definition()); 01818 newMd->enableCallGraph(root->callGraph); 01819 newMd->enableCallerGraph(root->callerGraph); 01820 newMd->setBitfields(md->bitfieldString()); 01821 newMd->addSectionsToDefinition(root->anchors); 01822 newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine()); 01823 newMd->setBodyDef(md->getBodyDef()); 01824 newMd->setInitializer(md->initializer()); 01825 newMd->setMaxInitLines(md->initializerLines()); 01826 newMd->setMemberGroupId(root->mGrpId); 01827 newMd->setMemberSpecifiers(md->getMemberSpecifiers()); 01828 01829 rootNav->releaseEntry(); 01830 } 01831 } 01832 } 01833 } 01834 } 01835 } 01836 } 01837 01838 } 01839 RECURSE_ENTRYTREE(findUsingDeclImports,rootNav); 01840 } 01841 01842 //---------------------------------------------------------------------- 01843 01844 static void findIncludedUsingDirectives() 01845 { 01846 // first mark all files as not visited 01847 FileNameListIterator fnli(*Doxygen::inputNameList); 01848 FileName *fn; 01849 for (fnli.toFirst();(fn=fnli.current());++fnli) 01850 { 01851 FileNameIterator fni(*fn); 01852 FileDef *fd; 01853 for (;(fd=fni.current());++fni) 01854 { 01855 fd->visited=FALSE; 01856 } 01857 } 01858 // then recursively add using directives found in #include files 01859 // to files that have not been visited. 01860 for (fnli.toFirst();(fn=fnli.current());++fnli) 01861 { 01862 FileNameIterator fni(*fn); 01863 FileDef *fd; 01864 for (fni.toFirst();(fd=fni.current());++fni) 01865 { 01866 if (!fd->visited) 01867 { 01868 //printf("----- adding using directives for file %s\n",fd->name().data()); 01869 fd->addIncludedUsingDirectives(); 01870 } 01871 } 01872 } 01873 } 01874 01875 //---------------------------------------------------------------------- 01876 01877 static MemberDef *addVariableToClass( 01878 EntryNav *rootNav, 01879 ClassDef *cd, 01880 MemberDef::MemberType mtype, 01881 const QCString &name, 01882 bool fromAnnScope, 01883 MemberDef *fromAnnMemb, 01884 Protection prot, 01885 bool related) 01886 { 01887 Entry *root = rootNav->entry(); 01888 01889 QCString qualScope = cd->qualifiedNameWithTemplateParameters(); 01890 QCString scopeSeparator="::"; 01891 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA")) 01892 { 01893 qualScope = substitute(qualScope,"::","."); 01894 scopeSeparator="."; 01895 } 01896 Debug::print(Debug::Variables,0, 01897 " class variable:\n" 01898 " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n", 01899 root->type.data(), 01900 qualScope.data(), 01901 name.data(), 01902 root->args.data(), 01903 root->protection, 01904 fromAnnScope, 01905 root->initializer.data() 01906 ); 01907 01908 QCString def; 01909 if (!root->type.isEmpty()) 01910 { 01911 if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES")) 01912 { 01913 def=root->type+" "+name+root->args; 01914 } 01915 else 01916 { 01917 def=root->type+" "+qualScope+scopeSeparator+name+root->args; 01918 } 01919 } 01920 else 01921 { 01922 if (Config_getBool("HIDE_SCOPE_NAMES")) 01923 { 01924 def=name+root->args; 01925 } 01926 else 01927 { 01928 def=qualScope+scopeSeparator+name+root->args; 01929 } 01930 } 01931 def.stripPrefix("static "); 01932 01933 // see if the member is already found in the same scope 01934 // (this may be the case for a static member that is initialized 01935 // outside the class) 01936 MemberName *mn=Doxygen::memberNameSDict->find(name); 01937 if (mn) 01938 { 01939 MemberNameIterator mni(*mn); 01940 MemberDef *md; 01941 for (mni.toFirst();(md=mni.current());++mni) 01942 { 01943 if (md->getClassDef()==cd && root->type==md->typeString()) 01944 // member already in the scope 01945 { 01946 addMemberDocs(rootNav,md,def,0,FALSE); 01947 //printf(" Member already found!\n"); 01948 return md; 01949 } 01950 } 01951 } 01952 // new member variable, typedef or enum value 01953 MemberDef *md=new MemberDef( 01954 root->fileName,root->startLine, 01955 root->type,name,root->args,0, 01956 prot,Normal,root->stat,related, 01957 mtype,0,0); 01958 md->setTagInfo(rootNav->tagInfo()); 01959 md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope()) 01960 //md->setDefFile(root->fileName); 01961 //md->setDefLine(root->startLine); 01962 md->setDocumentation(root->doc,root->docFile,root->docLine); 01963 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 01964 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 01965 md->setDefinition(def); 01966 md->setBitfields(root->bitfields); 01967 md->addSectionsToDefinition(root->anchors); 01968 md->setFromAnonymousScope(fromAnnScope); 01969 md->setFromAnonymousMember(fromAnnMemb); 01970 //md->setIndentDepth(indentDepth); 01971 md->setBodySegment(root->bodyLine,root->endBodyLine); 01972 md->setInitializer(root->initializer); 01973 md->setMaxInitLines(root->initLines); 01974 md->setMemberGroupId(root->mGrpId); 01975 md->setMemberSpecifiers(root->spec); 01976 md->setReadAccessor(root->read); 01977 md->setWriteAccessor(root->write); 01978 md->enableCallGraph(root->callGraph); 01979 md->enableCallerGraph(root->callerGraph); 01980 md->setHidden(root->hidden); 01981 md->setArtificial(root->artificial); 01982 addMemberToGroups(root,md); 01983 //if (root->mGrpId!=-1) 01984 //{ 01985 // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId); 01986 // md->setMemberGroup(memberGroupDict[root->mGrpId]); 01987 // 01988 md->setBodyDef(rootNav->fileDef()); 01989 01990 //printf("Adding member=%s\n",md->name().data()); 01991 // add the member to the global list 01992 if (mn) 01993 { 01994 mn->append(md); 01995 } 01996 else // new variable name 01997 { 01998 mn = new MemberName(name); 01999 mn->append(md); 02000 //printf("Adding memberName=%s\n",mn->memberName()); 02001 //Doxygen::memberNameDict.insert(name,mn); 02002 //Doxygen::memberNameList.append(mn); 02003 Doxygen::memberNameSDict->append(name,mn); 02004 // add the member to the class 02005 } 02006 //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd); 02007 cd->insertMember(md); 02008 md->setRefItems(root->sli); 02009 02010 //TODO: insert FileDef instead of filename strings. 02011 cd->insertUsedFile(root->fileName); 02012 rootNav->changeSection(Entry::EMPTY_SEC); 02013 return md; 02014 } 02015 02016 //---------------------------------------------------------------------- 02017 02018 static MemberDef *addVariableToFile( 02019 EntryNav *rootNav, 02020 MemberDef::MemberType mtype, 02021 const QCString &scope, 02022 const QCString &name, 02023 bool fromAnnScope, 02024 /*int indentDepth,*/ 02025 MemberDef *fromAnnMemb) 02026 { 02027 Entry *root = rootNav->entry(); 02028 Debug::print(Debug::Variables,0, 02029 " global variable:\n" 02030 " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d\n", 02031 root->type.data(), 02032 scope.data(), 02033 name.data(), 02034 root->args.data(), 02035 root->protection, 02036 mtype 02037 ); 02038 02039 FileDef *fd = rootNav->fileDef(); 02040 02041 // see if the function is inside a namespace 02042 NamespaceDef *nd = 0; 02043 QCString nscope; 02044 if (!scope.isEmpty()) 02045 { 02046 nscope=removeAnonymousScopes(scope); 02047 if (!nscope.isEmpty()) 02048 { 02049 nd = getResolvedNamespace(nscope); 02050 } 02051 } 02052 QCString def; 02053 02054 // determine the definition of the global variable 02055 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && 02056 !Config_getBool("HIDE_SCOPE_NAMES") 02057 ) 02058 // variable is inside a namespace, so put the scope before the name 02059 { 02060 static bool optimizeForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); 02061 QCString sep="::"; 02062 if (optimizeForJava) sep="."; 02063 02064 if (!root->type.isEmpty()) 02065 { 02066 def=root->type+" "+nd->name()+sep+name+root->args; 02067 } 02068 else 02069 { 02070 def=nd->name()+sep+name+root->args; 02071 } 02072 } 02073 else 02074 { 02075 if (!root->type.isEmpty() && !root->name.isEmpty()) 02076 { 02077 if (name.at(0)=='@') // dummy variable representing annonymous union 02078 def=root->type; 02079 else 02080 def=root->type+" "+name+root->args; 02081 } 02082 else 02083 { 02084 def=name+root->args; 02085 } 02086 } 02087 def.stripPrefix("static "); 02088 02089 MemberName *mn=Doxygen::functionNameSDict->find(name); 02090 if (mn) 02091 { 02092 //QCString nscope=removeAnonymousScopes(scope); 02093 //NamespaceDef *nd=0; 02094 //if (!nscope.isEmpty()) 02095 //{ 02096 // nd = getResolvedNamespace(nscope); 02097 //} 02098 MemberNameIterator mni(*mn); 02099 MemberDef *md; 02100 for (mni.toFirst();(md=mni.current());++mni) 02101 { 02102 if ( 02103 ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && 02104 root->fileName==md->getFileDef()->absFilePath() 02105 ) // both variable names in the same file 02106 || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace 02107 ) 02108 && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables 02109 ) 02110 // variable already in the scope 02111 { 02112 if (md->getFileDef() && 02113 ! // not a php array 02114 ( 02115 (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) && 02116 (md->argsString()!=root->args && root->args.find('[')!=-1) 02117 ) 02118 ) 02119 // not a php array variable 02120 { 02121 02122 Debug::print(Debug::Variables,0, 02123 " variable already found: scope=%s\n",md->getOuterScope()->name().data()); 02124 addMemberDocs(rootNav,md,def,0,FALSE); 02125 md->setRefItems(root->sli); 02126 return md; 02127 } 02128 } 02129 } 02130 } 02131 Debug::print(Debug::Variables,0, 02132 " new variable, nd=%s!\n",nd?nd->name().data():"<global>"); 02133 // new global variable, enum value or typedef 02134 MemberDef *md=new MemberDef( 02135 root->fileName,root->startLine, 02136 root->type,name,root->args,0, 02137 Public, Normal,root->stat,FALSE, 02138 mtype,0,0); 02139 md->setTagInfo(rootNav->tagInfo()); 02140 md->setDocumentation(root->doc,root->docFile,root->docLine); 02141 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 02142 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 02143 md->addSectionsToDefinition(root->anchors); 02144 md->setFromAnonymousScope(fromAnnScope); 02145 md->setFromAnonymousMember(fromAnnMemb); 02146 md->setInitializer(root->initializer); 02147 md->setMaxInitLines(root->initLines); 02148 md->setMemberGroupId(root->mGrpId); 02149 md->setDefinition(def); 02150 md->enableCallGraph(root->callGraph); 02151 md->enableCallerGraph(root->callerGraph); 02152 md->setExplicitExternal(root->explicitExternal); 02153 //md->setOuterScope(fd); 02154 if (!root->explicitExternal) 02155 { 02156 md->setBodySegment(root->bodyLine,root->endBodyLine); 02157 md->setBodyDef(fd); 02158 } 02159 addMemberToGroups(root,md); 02160 02161 md->setRefItems(root->sli); 02162 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') 02163 { 02164 md->setNamespace(nd); 02165 nd->insertMember(md); 02166 } 02167 02168 // add member to the file (we do this even if we have already inserted 02169 // it into the namespace. 02170 if (fd) 02171 { 02172 md->setFileDef(fd); 02173 fd->insertMember(md); 02174 } 02175 02176 // add member definition to the list of globals 02177 if (mn) 02178 { 02179 mn->append(md); 02180 } 02181 else 02182 { 02183 mn = new MemberName(name); 02184 mn->append(md); 02185 Doxygen::functionNameSDict->append(name,mn); 02186 } 02187 rootNav->changeSection(Entry::EMPTY_SEC); 02188 return md; 02189 } 02190 02195 static int findFunctionPtr(const QCString &type,int *pLength=0) 02196 { 02197 static const QRegExp re("([^)]*\\*[^)]*)"); 02198 int i=-1,l; 02199 if (!type.isEmpty() && // return type is non-empty 02200 (i=re.match(type,0,&l))!=-1 && // contains (...*...) 02201 type.find("operator")==-1 && // not an operator 02202 (type.find(")(")==-1 || type.find("typedef ")!=-1) 02203 // not a function pointer return type 02204 ) 02205 { 02206 if (pLength) *pLength=l; 02207 return i; 02208 } 02209 else 02210 { 02211 return -1; 02212 } 02213 } 02214 02215 02219 static bool isVarWithConstructor(EntryNav *rootNav) 02220 { 02221 static QRegExp initChars("[0-9\"'&*!^]+"); 02222 static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*"); 02223 bool result=FALSE; 02224 bool typeIsClass; 02225 QCString type; 02226 Definition *ctx = 0; 02227 FileDef *fd = 0; 02228 int ti; 02229 02230 //printf("isVarWithConstructor(%s)\n",rootNav->name().data()); 02231 rootNav->loadEntry(g_storage); 02232 Entry *root = rootNav->entry(); 02233 02234 if (rootNav->parent()->section() & Entry::COMPOUND_MASK) 02235 { // inside a class 02236 result=FALSE; 02237 goto done; 02238 } 02239 else if ((fd = rootNav->fileDef()) && 02240 fd->name().right(2)==".c" 02241 ) 02242 { // inside a .c file 02243 result=FALSE; 02244 goto done; 02245 } 02246 if (root->type.isEmpty()) 02247 { 02248 result=FALSE; 02249 goto done; 02250 } 02251 if (!rootNav->parent()->name().isEmpty()) 02252 { 02253 ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name()); 02254 } 02255 type = root->type; 02256 // remove qualifiers 02257 findAndRemoveWord(type,"const"); 02258 findAndRemoveWord(type,"static"); 02259 findAndRemoveWord(type,"volatile"); 02260 //if (type.left(6)=="const ") type=type.right(type.length()-6); 02261 typeIsClass=getResolvedClass(ctx,fd,type)!=0; 02262 if (!typeIsClass && (ti=type.find('<'))!=-1) 02263 { 02264 typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0; 02265 } 02266 if (typeIsClass) // now we still have to check if the arguments are 02267 // types or values. Since we do not have complete type info 02268 // we need to rely on heuristics :-( 02269 { 02270 //printf("typeIsClass\n"); 02271 ArgumentList *al = root->argList; 02272 if (al==0 || al->isEmpty()) 02273 { 02274 result=FALSE; // empty arg list -> function prototype. 02275 goto done; 02276 } 02277 ArgumentListIterator ali(*al); 02278 Argument *a; 02279 for (ali.toFirst();(a=ali.current());++ali) 02280 { 02281 if (!a->name.isEmpty() || !a->defval.isEmpty()) 02282 { 02283 if (a->name.find(initChars)==0) 02284 { 02285 result=TRUE; 02286 } 02287 else 02288 { 02289 result=FALSE; // arg has (type,name) pair -> function prototype 02290 } 02291 goto done; 02292 } 02293 if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) 02294 { 02295 result=FALSE; // arg type is a known type 02296 goto done; 02297 } 02298 if (checkIfTypedef(ctx,fd,a->type)) 02299 { 02300 //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__); 02301 result=FALSE; // argument is a typedef 02302 goto done; 02303 } 02304 if (a->type.at(a->type.length()-1)=='*' || 02305 a->type.at(a->type.length()-1)=='&') 02306 // type ends with * or & => pointer or reference 02307 { 02308 result=FALSE; 02309 goto done; 02310 } 02311 if (a->type.find(initChars)==0) 02312 { 02313 result=TRUE; // argument type starts with typical initializer char 02314 goto done; 02315 } 02316 QCString resType=resolveTypeDef(ctx,a->type); 02317 if (resType.isEmpty()) resType=a->type; 02318 int len; 02319 if (idChars.match(resType,0,&len)==0) // resType starts with identifier 02320 { 02321 resType=resType.left(len); 02322 //printf("resType=%s\n",resType.data()); 02323 if (resType=="int" || resType=="long" || resType=="float" || 02324 resType=="double" || resType=="char" || resType=="signed" || 02325 resType=="const" || resType=="unsigned" || resType=="void") 02326 { 02327 result=FALSE; // type keyword -> function prototype 02328 goto done; 02329 } 02330 } 02331 } 02332 result=TRUE; 02333 } 02334 02335 done: 02336 rootNav->releaseEntry(); 02337 //printf("isVarWithConstructor(%s,%s)=%d\n",root->parent->name.data(), 02338 // root->type.data(),result); 02339 return result; 02340 } 02341 02342 //---------------------------------------------------------------------- 02343 // Searches the Entry tree for Variable documentation sections. 02344 // If found they are stored in their class or in the global list. 02345 02346 static void buildVarList(EntryNav *rootNav) 02347 { 02348 //printf("buildVarList(%s)\n",rootNav->name().data()); 02349 int isFuncPtr=-1; 02350 if (!rootNav->name().isEmpty() && 02351 (rootNav->type().isEmpty() || compoundKeywordDict.find(rootNav->type())==0) && 02352 ( 02353 (rootNav->section()==Entry::VARIABLE_SEC // it's a variable 02354 ) || 02355 (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable 02356 (isFuncPtr=findFunctionPtr(rootNav->type()))!=-1 02357 ) || 02358 (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor 02359 isVarWithConstructor(rootNav) 02360 ) 02361 ) 02362 ) // documented variable 02363 { 02364 rootNav->loadEntry(g_storage); 02365 Entry *root = rootNav->entry(); 02366 02367 Debug::print(Debug::Variables,0, 02368 "VARIABLE_SEC: \n" 02369 " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d\n", 02370 root->type.data(), 02371 root->name.data(), 02372 root->args.data(), 02373 root->bodyLine, 02374 root->mGrpId 02375 ); 02376 //printf("root->parent->name=%s\n",root->parent->name.data()); 02377 02378 if (root->type.isEmpty() && root->name.find("operator")==-1 && 02379 (root->name.find('*')!=-1 || root->name.find('&')!=-1)) 02380 { 02381 // recover from parse error caused by redundant braces 02382 // like in "int *(var[10]);", which is parsed as 02383 // type="" name="int *" args="(var[10])" 02384 02385 root->type=root->name; 02386 static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*"); 02387 int l; 02388 int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l); 02389 root->name=root->args.mid(i,l); 02390 root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l); 02391 //printf("new: type=`%s' name=`%s' args=`%s'\n", 02392 // root->type.data(),root->name.data(),root->args.data()); 02393 } 02394 else 02395 { 02396 int i=isFuncPtr; 02397 if (i==-1) i=findFunctionPtr(root->type); // for typedefs isFuncPtr is not yet set 02398 if (i!=-1) // function pointer 02399 { 02400 int ai = root->type.find('[',i); 02401 if (ai>i) // function pointer array 02402 { 02403 root->args.prepend(root->type.right(root->type.length()-ai)); 02404 root->type=root->type.left(ai); 02405 } 02406 else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]" 02407 { 02408 root->type=root->type.left(root->type.length()-1); 02409 root->args.prepend(")"); 02410 //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data()); 02411 } 02412 } 02413 else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int) 02414 { 02415 root->type=root->type.left(root->type.length()-1); 02416 root->args.prepend(")"); 02417 } 02418 } 02419 02420 QCString scope,name=removeRedundantWhiteSpace(root->name); 02421 02422 // find the scope of this variable 02423 EntryNav *p = rootNav->parent(); 02424 while ((p->section() & Entry::SCOPE_MASK)) 02425 { 02426 QCString scopeName = p->name(); 02427 if (!scopeName.isEmpty()) 02428 { 02429 scope.prepend(scopeName); 02430 break; 02431 } 02432 p=p->parent(); 02433 } 02434 02435 MemberDef::MemberType mtype; 02436 QCString type=root->type.stripWhiteSpace(); 02437 ClassDef *cd=0; 02438 bool isRelated=FALSE; 02439 02440 QCString classScope=stripAnonymousNamespaceScope(scope); 02441 classScope=stripTemplateSpecifiersFromScope(classScope,FALSE); 02442 QCString annScopePrefix=scope.left(scope.length()-classScope.length()); 02443 02444 if (root->name.findRev("::")!=-1) 02445 { 02446 if (root->type=="friend class" || root->type=="friend struct" || 02447 root->type=="friend union") 02448 { 02449 cd=getClass(scope); 02450 if (cd) 02451 { 02452 addVariableToClass(rootNav, // entry 02453 cd, // class to add member to 02454 MemberDef::Friend, // type of member 02455 name, // name of the member 02456 FALSE, // from Anonymous scope 02457 0, // anonymous member 02458 Public, // protection 02459 FALSE // related to a class 02460 ); 02461 } 02462 } 02463 goto nextMember; 02464 /* skip this member, because it is a 02465 * static variable definition (always?), which will be 02466 * found in a class scope as well, but then we know the 02467 * correct protection level, so only then it will be 02468 * inserted in the correct list! 02469 */ 02470 } 02471 02472 if (type=="@") 02473 mtype=MemberDef::EnumValue; 02474 else if (type.left(8)=="typedef ") 02475 mtype=MemberDef::Typedef; 02476 else if (type.left(7)=="friend ") 02477 mtype=MemberDef::Friend; 02478 else if (root->mtype==Property) 02479 mtype=MemberDef::Property; 02480 else if (root->mtype==Event) 02481 mtype=MemberDef::Event; 02482 else 02483 mtype=MemberDef::Variable; 02484 02485 #if 0 // does not work correctly 02486 //static bool typedefHidesStruct = Config_getBool("TYPEDEF_HIDES_STRUCT"); 02487 if (typedefHidesStruct) // substitute names with typedef'ed names 02488 { 02489 QCString baseType = type; 02490 baseType.stripPrefix("typedef "); 02491 if (baseType.stripPrefix("enum ")) 02492 { 02493 MemberName *mn=Doxygen::functionNameSDict->find(baseType.stripWhiteSpace()); 02494 MemberNameIterator mni(*mn); 02495 MemberDef *md; 02496 for (mni.toFirst();(md=mni.current());++mni) 02497 { 02498 if (md->isEnumerate()) 02499 { 02500 md->setName(name); 02501 md->setDefinition(name); 02502 goto nextMember; 02503 } 02504 } 02505 } 02506 else 02507 { 02508 baseType.stripPrefix("struct "); 02509 baseType.stripPrefix("union "); 02510 { 02511 ClassDef *typedefClass = Doxygen::classSDict->find(baseType); 02512 if (typedefClass) 02513 { 02514 typedefClass->setName(name); 02515 typedefClass->setClassName(name); 02516 goto nextMember; 02517 } 02518 } 02519 } 02520 } 02521 #endif 02522 02523 if (!root->relates.isEmpty()) // related variable 02524 { 02525 isRelated=TRUE; 02526 if (getClass(root->relates)==0 && !scope.isEmpty()) 02527 scope=mergeScopes(scope,root->relates); 02528 else 02529 scope=root->relates; 02530 } 02531 02532 cd=getClass(scope); 02533 if (cd==0 && classScope!=scope) cd=getClass(classScope); 02534 if (cd) 02535 { 02536 MemberDef *md=0; 02537 02538 // if cd is an annonymous scope we insert the member 02539 // into a non-annonymous scope as well. This is needed to 02540 // be able to refer to it using \var or \fn 02541 02542 //int indentDepth=0; 02543 int si=scope.find('@'); 02544 //int anonyScopes = 0; 02545 bool added=FALSE; 02546 02547 if (si!=-1) // anonymous scope 02548 { 02549 QCString pScope; 02550 ClassDef *pcd=0; 02551 pScope = scope.left(QMAX(si-2,0)); 02552 if (!pScope.isEmpty()) 02553 pScope.prepend(annScopePrefix); 02554 else if (annScopePrefix.length()>2) 02555 pScope=annScopePrefix.left(annScopePrefix.length()-2); 02556 if (name.at(0)!='@') 02557 { 02558 if (!pScope.isEmpty() && (pcd=getClass(pScope))) 02559 { 02560 md=addVariableToClass(rootNav, // entry 02561 pcd, // class to add member to 02562 mtype, // member type 02563 name, // member name 02564 TRUE, // from anonymous scope 02565 0, // from anonymous member 02566 root->protection, 02567 isRelated 02568 ); 02569 added=TRUE; 02570 } 02571 else // anonymous scope inside namespace or file => put variable in the global scope 02572 { 02573 if (mtype==MemberDef::Variable) 02574 { 02575 md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); 02576 } 02577 added=TRUE; 02578 } 02579 } 02580 } 02581 //printf("name=`%s' scope=%s scope.right=%s\n", 02582 // name.data(),scope.data(), 02583 // scope.right(scope.length()-si).data()); 02584 addVariableToClass(rootNav, // entry 02585 cd, // class to add member to 02586 mtype, // member type 02587 name, // name of the member 02588 FALSE, // from anonymous scope 02589 md, // from anonymous member 02590 root->protection, 02591 isRelated); 02592 } 02593 else if (!name.isEmpty()) // global variable 02594 { 02595 //printf("Inserting member in global scope %s!\n",scope.data()); 02596 addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0); 02597 } 02598 nextMember: 02599 02600 rootNav->releaseEntry(); 02601 } 02602 if (rootNav->children()) 02603 { 02604 EntryNavListIterator eli(*rootNav->children()); 02605 EntryNav *e; 02606 for (;(e=eli.current());++eli) 02607 { 02608 if (e->section()!=Entry::ENUM_SEC) 02609 { 02610 buildVarList(e); 02611 } 02612 } 02613 } 02614 } 02615 02616 //---------------------------------------------------------------------- 02617 // Searches the Entry tree for Function sections. 02618 // If found they are stored in their class or in the global list. 02619 02620 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd, 02621 const QCString &rname,bool isFriend) 02622 { 02623 Entry *root = rootNav->entry(); 02624 FileDef *fd=rootNav->fileDef(); 02625 02626 int l,i=-1; 02627 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*"); 02628 02629 if (!root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable 02630 { 02631 root->args+=root->type.right(root->type.length()-i-l); 02632 root->type=root->type.left(i+l); 02633 } 02634 02635 QCString name=removeRedundantWhiteSpace(rname); 02636 if (name.left(2)=="::") name=name.right(name.length()-2); 02637 02638 MemberDef::MemberType mtype; 02639 if (isFriend) mtype=MemberDef::Friend; 02640 else if (root->mtype==Signal) mtype=MemberDef::Signal; 02641 else if (root->mtype==Slot) mtype=MemberDef::Slot; 02642 else if (root->mtype==DCOP) mtype=MemberDef::DCOP; 02643 else mtype=MemberDef::Function; 02644 02645 // strip redundant template specifier for constructors 02646 if ((fd==0 || getLanguageFromFileName(fd->name())==SrcLangExt_Cpp) && 02647 name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1) 02648 { 02649 name=name.left(i); 02650 } 02651 02652 //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", 02653 // root->name.data(),root->args.data(),argListToString(root->argList).data() 02654 // ); 02655 02656 // adding class member 02657 MemberDef *md=new MemberDef( 02658 root->fileName,root->startLine, 02659 root->type,name,root->args,root->exception, 02660 root->protection,root->virt,root->stat,!root->relates.isEmpty(), 02661 mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList); 02662 md->setTagInfo(rootNav->tagInfo()); 02663 md->setMemberClass(cd); 02664 md->setDocumentation(root->doc,root->docFile,root->docLine); 02665 md->setDocsForDefinition(!root->proto); 02666 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 02667 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 02668 md->setBodySegment(root->bodyLine,root->endBodyLine); 02669 md->setMemberSpecifiers(root->spec); 02670 md->setMemberGroupId(root->mGrpId); 02671 md->setTypeConstraints(root->typeConstr); 02672 md->setBodyDef(fd); 02673 md->setFileDef(fd); 02674 //md->setScopeTemplateArguments(root->tArgList); 02675 md->addSectionsToDefinition(root->anchors); 02676 QCString def; 02677 QCString qualScope = cd->qualifiedNameWithTemplateParameters(); 02678 QCString scopeSeparator="::"; 02679 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA")) 02680 { 02681 qualScope = substitute(qualScope,"::","."); 02682 scopeSeparator="."; 02683 } 02684 if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES")) 02685 { 02686 if (!root->type.isEmpty()) 02687 { 02688 if (root->argList) 02689 { 02690 def=root->type+" "+name; 02691 } 02692 else 02693 { 02694 def=root->type+" "+name+root->args; 02695 } 02696 } 02697 else 02698 { 02699 if (root->argList) 02700 { 02701 def=name; 02702 } 02703 else 02704 { 02705 def=name+root->args; 02706 } 02707 } 02708 } 02709 else 02710 { 02711 if (!root->type.isEmpty()) 02712 { 02713 if (root->argList) 02714 { 02715 def=root->type+" "+qualScope+scopeSeparator+name; 02716 } 02717 else 02718 { 02719 def=root->type+" "+qualScope+scopeSeparator+name+root->args; 02720 } 02721 } 02722 else 02723 { 02724 if (root->argList) 02725 { 02726 def=qualScope+scopeSeparator+name; 02727 } 02728 else 02729 { 02730 def=qualScope+scopeSeparator+name+root->args; 02731 } 02732 } 02733 } 02734 if (def.left(7)=="friend ") def=def.right(def.length()-7); 02735 md->setDefinition(def); 02736 md->enableCallGraph(root->callGraph); 02737 md->enableCallerGraph(root->callerGraph); 02738 02739 Debug::print(Debug::Functions,0, 02740 " Func Member:\n" 02741 " `%s' `%s'::`%s' `%s' proto=%d\n" 02742 " def=`%s'\n", 02743 root->type.data(), 02744 qualScope.data(), 02745 rname.data(), 02746 root->args.data(), 02747 root->proto, 02748 def.data() 02749 ); 02750 02751 // add member to the global list of all members 02752 //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data()); 02753 MemberName *mn; 02754 if ((mn=Doxygen::memberNameSDict->find(name))) 02755 { 02756 mn->append(md); 02757 } 02758 else 02759 { 02760 mn = new MemberName(name); 02761 mn->append(md); 02762 Doxygen::memberNameSDict->append(name,mn); 02763 } 02764 02765 // add member to the class cd 02766 cd->insertMember(md); 02767 // add file to list of used files 02768 cd->insertUsedFile(root->fileName); 02769 02770 addMemberToGroups(root,md); 02771 rootNav->changeSection(Entry::EMPTY_SEC); 02772 md->setRefItems(root->sli); 02773 } 02774 02775 02776 static void buildFunctionList(EntryNav *rootNav) 02777 { 02778 if (rootNav->section()==Entry::FUNCTION_SEC) 02779 { 02780 rootNav->loadEntry(g_storage); 02781 Entry *root = rootNav->entry(); 02782 02783 Debug::print(Debug::Functions,0, 02784 "FUNCTION_SEC:\n" 02785 " `%s' `%s'::`%s' `%s' relates=`%s' relatesDup=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%d proto=%d docFile=%s\n", 02786 root->type.data(), 02787 rootNav->parent()->name().data(), 02788 root->name.data(), 02789 root->args.data(), 02790 root->relates.data(), 02791 root->relatesDup, 02792 root->fileName.data(), 02793 root->startLine, 02794 root->bodyLine, 02795 root->tArgLists ? (int)root->tArgLists->count() : -1, 02796 root->mGrpId, 02797 root->spec, 02798 root->proto, 02799 root->docFile.data() 02800 ); 02801 02802 bool isFriend=root->type.find("friend ")!=-1; 02803 QCString rname = removeRedundantWhiteSpace(root->name); 02804 //printf("rname=%s\n",rname.data()); 02805 02806 if (!rname.isEmpty()) 02807 { 02808 02809 ClassDef *cd=0; 02810 // check if this function's parent is a class 02811 QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name); 02812 scope=stripTemplateSpecifiersFromScope(scope,FALSE); 02813 02814 FileDef *rfd=rootNav->fileDef(); 02815 02816 int memIndex=rname.findRev("::"); 02817 02818 cd=getClass(scope); 02819 if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A 02820 { 02821 // strip scope from name 02822 rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); 02823 } 02824 02825 NamespaceDef *nd = 0; 02826 bool isMember=FALSE; 02827 if (memIndex!=-1) 02828 { 02829 int ts=rname.find('<'); 02830 int te=rname.find('>'); 02831 if (memIndex>0 && (ts==-1 || te==-1)) 02832 { 02833 nd = Doxygen::namespaceSDict->find(rname.left(memIndex)); 02834 isMember = nd==0; 02835 if (nd) 02836 { 02837 // strip namespace scope from name 02838 scope=rname.left(memIndex); 02839 rname=rname.right(rname.length()-memIndex-2); 02840 } 02841 } 02842 else 02843 { 02844 isMember=memIndex<ts || memIndex>te; 02845 } 02846 02847 } 02848 02849 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*"); 02850 if (!rootNav->parent()->name().isEmpty() && 02851 (rootNav->parent()->section() & Entry::COMPOUND_MASK) && 02852 cd && 02853 // do some fuzzy things to exclude function pointers 02854 (root->type.isEmpty() || 02855 (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) || // type contains ..(..* and args not )[.. -> function pointer 02856 root->type.find(")(")!=-1 || root->type.find("operator")!=-1 // type contains ..)(.. and not "operator" 02857 ) 02858 ) 02859 { 02860 Debug::print(Debug::Functions,0," --> member %s of class %s!\n", 02861 rname.data(),cd->name().data()); 02862 addMethodToClass(rootNav,cd,rname,isFriend); 02863 } 02864 else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) 02865 || rootNav->parent()->section()==Entry::OBJCIMPL_SEC 02866 ) && 02867 !isMember && 02868 (root->relates.isEmpty() || root->relatesDup) && 02869 root->type.left(7)!="extern " && root->type.left(8)!="typedef " 02870 ) 02871 // no member => unrelated function 02872 { 02873 /* check the uniqueness of the function name in the file. 02874 * A file could contain a function prototype and a function definition 02875 * or even multiple function prototypes. 02876 */ 02877 bool found=FALSE; 02878 MemberName *mn; 02879 MemberDef *md=0; 02880 if ((mn=Doxygen::functionNameSDict->find(rname))) 02881 { 02882 Debug::print(Debug::Functions,0," --> function %s already found!\n",rname.data()); 02883 MemberNameIterator mni(*mn); 02884 for (mni.toFirst();(!found && (md=mni.current()));++mni) 02885 { 02886 NamespaceDef *mnd = md->getNamespaceDef(); 02887 NamespaceDef *rnd = 0; 02888 //printf("root namespace=%s\n",rootNav->parent()->name().data()); 02889 QCString fullScope = scope; 02890 QCString parentScope = rootNav->parent()->name(); 02891 if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope)) 02892 { 02893 if (!scope.isEmpty()) fullScope.prepend("::"); 02894 fullScope.prepend(parentScope); 02895 } 02896 //printf("fullScope=%s\n",fullScope.data()); 02897 rnd = getResolvedNamespace(fullScope); 02898 FileDef *mfd = md->getFileDef(); 02899 QCString nsName,rnsName; 02900 if (mnd) nsName = mnd->name().copy(); 02901 if (rnd) rnsName = rnd->name().copy(); 02902 //printf("matching arguments for %s%s %s%s\n", 02903 // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data()); 02904 LockingPtr<ArgumentList> mdAl = md->argumentList(); 02905 if ( 02906 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(), 02907 rnd ? rnd : Doxygen::globalScope,rfd,root->argList, 02908 FALSE) 02909 ) 02910 { 02911 GroupDef *gd=0; 02912 if (root->groups->first()!=0) 02913 { 02914 gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data()); 02915 } 02916 //printf("match!\n"); 02917 //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data()); 02918 // see if we need to create a new member 02919 found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace 02920 ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and 02921 mfd->absFilePath()==root->fileName // prototype in the same file 02922 ) 02923 ); 02924 // otherwise, allow a duplicate global member with the same argument list 02925 if (!found && gd && gd==md->getGroupDef()) 02926 { 02927 // member is already in the group, so we don't want to add it again. 02928 found=TRUE; 02929 } 02930 02931 //printf("combining function with prototype found=%d in namespace %s\n", 02932 // found,nsName.data()); 02933 02934 if (found) 02935 { 02936 // merge argument lists 02937 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty()); 02938 // merge documentation 02939 if (md->documentation().isEmpty() && !root->doc.isEmpty()) 02940 { 02941 ArgumentList *argList = new ArgumentList; 02942 stringToArgumentList(root->args,argList); 02943 if (root->proto) 02944 { 02945 //printf("setDeclArgumentList to %p\n",argList); 02946 md->setDeclArgumentList(argList); 02947 } 02948 else 02949 { 02950 md->setArgumentList(argList); 02951 } 02952 } 02953 #if 0 02954 else if (!md->documentation().isEmpty() && !root->doc.isEmpty() && mnd==rnd) 02955 { 02956 warn(root->docFile,root->docLine,"Warning: member %s: ignoring the detailed description found here, since another one was found at line %d of file %s!",md->name().data(),md->docLine(),md->docFile().data()); 02957 //printf("md->docs=[%s] root->docs=[%s]\n",md->documentation().data(),root->doc.data()); 02958 } 02959 #endif 02960 md->setDocumentation(root->doc,root->docFile,root->docLine); 02961 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 02962 md->setDocsForDefinition(!root->proto); 02963 02964 if (md->briefDescription().isEmpty() && !root->brief.isEmpty()) 02965 { 02966 md->setArgsString(root->args); 02967 } 02968 #if 0 02969 else if (!md->briefDescription().isEmpty() && !root->brief.isEmpty() && mnd==rnd) 02970 { 02971 warn(root->briefFile,root->briefLine,"Warning: member %s: ignoring the brief description found here, since another one was found at line %d of file %s!",md->name().data(),md->briefLine(),md->briefFile().data()); 02972 } 02973 #endif 02974 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 02975 02976 md->addSectionsToDefinition(root->anchors); 02977 02978 md->enableCallGraph(md->hasCallGraph() || root->callGraph); 02979 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph); 02980 02981 // merge ingroup specifiers 02982 if (md->getGroupDef()==0 && root->groups->first()!=0) 02983 { 02984 addMemberToGroups(root,md); 02985 } 02986 else if (md->getGroupDef()!=0 && root->groups->count()==0) 02987 { 02988 //printf("existing member is grouped, new member not\n"); 02989 root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri())); 02990 } 02991 else if (md->getGroupDef()!=0 && root->groups->first()!=0) 02992 { 02993 //printf("both members are grouped\n"); 02994 } 02995 } 02996 } 02997 } 02998 } 02999 if (!found) /* global function is unique with respect to the file */ 03000 { 03001 Debug::print(Debug::Functions,0," --> new function %s found!\n",rname.data()); 03002 //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n", 03003 // root->type.data(),rname.data(),root->args.data(),root->bodyLine); 03004 03005 // new global function 03006 ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0; 03007 QCString name=removeRedundantWhiteSpace(rname); 03008 md=new MemberDef( 03009 root->fileName,root->startLine, 03010 root->type,name,root->args,root->exception, 03011 root->protection,root->virt,root->stat,FALSE, 03012 MemberDef::Function,tArgList,root->argList); 03013 03014 md->setTagInfo(rootNav->tagInfo()); 03015 //md->setDefFile(root->fileName); 03016 //md->setDefLine(root->startLine); 03017 md->setDocumentation(root->doc,root->docFile,root->docLine); 03018 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 03019 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 03020 md->setPrototype(root->proto); 03021 md->setDocsForDefinition(!root->proto); 03022 md->setTypeConstraints(root->typeConstr); 03023 //md->setBody(root->body); 03024 md->setBodySegment(root->bodyLine,root->endBodyLine); 03025 FileDef *fd=rootNav->fileDef(); 03026 md->setBodyDef(fd); 03027 md->addSectionsToDefinition(root->anchors); 03028 md->setMemberSpecifiers(root->spec); 03029 md->setMemberGroupId(root->mGrpId); 03030 03031 // see if the function is inside a namespace that was not part of 03032 // the name already (in that case nd should be non-zero already) 03033 if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC ) 03034 { 03035 QCString nscope=removeAnonymousScopes(rootNav->parent()->name()); 03036 if (!nscope.isEmpty()) 03037 { 03038 nd = getResolvedNamespace(nscope); 03039 } 03040 } 03041 03042 if (!scope.isEmpty()) 03043 { 03044 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA")) 03045 { 03046 scope = substitute(scope,"::",".")+"."; 03047 } 03048 else 03049 { 03050 scope+="::"; 03051 } 03052 } 03053 03054 QCString def; 03055 if (!root->type.isEmpty()) 03056 { 03057 if (root->argList) 03058 { 03059 def=root->type+" "+scope+name; 03060 } 03061 else 03062 { 03063 def=root->type+" "+scope+name+root->args; 03064 } 03065 } 03066 else 03067 { 03068 if (root->argList) 03069 { 03070 def=scope+name.copy(); 03071 } 03072 else 03073 { 03074 def=scope+name+root->args; 03075 } 03076 } 03077 Debug::print(Debug::Functions,0, 03078 " Global Function:\n" 03079 " `%s' `%s'::`%s' `%s' proto=%d\n" 03080 " def=`%s'\n", 03081 root->type.data(), 03082 rootNav->parent()->name().data(), 03083 rname.data(), 03084 root->args.data(), 03085 root->proto, 03086 def.data() 03087 ); 03088 md->setDefinition(def); 03089 md->enableCallGraph(root->callGraph); 03090 md->enableCallerGraph(root->callerGraph); 03091 //if (root->mGrpId!=-1) 03092 //{ 03093 // md->setMemberGroup(memberGroupDict[root->mGrpId]); 03094 //} 03095 03096 md->setRefItems(root->sli); 03097 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') 03098 { 03099 // add member to namespace 03100 md->setNamespace(nd); 03101 nd->insertMember(md); 03102 } 03103 if (fd) 03104 { 03105 // add member to the file (we do this even if we have already 03106 // inserted it into the namespace) 03107 md->setFileDef(fd); 03108 fd->insertMember(md); 03109 } 03110 03111 // add member to the list of file members 03112 //printf("Adding member=%s\n",md->name().data()); 03113 MemberName *mn; 03114 if ((mn=Doxygen::functionNameSDict->find(name))) 03115 { 03116 mn->append(md); 03117 } 03118 else 03119 { 03120 mn = new MemberName(name); 03121 mn->append(md); 03122 Doxygen::functionNameSDict->append(name,mn); 03123 } 03124 addMemberToGroups(root,md); 03125 if (!root->relatesDup) // if this is a relatesalso command, allow find 03126 // Member to pick it up 03127 { 03128 rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished 03129 // with this entry. 03130 03131 } 03132 } 03133 else 03134 { 03135 FileDef *fd=rootNav->fileDef(); 03136 if (fd) 03137 { 03138 // add member to the file (we do this even if we have already 03139 // inserted it into the namespace) 03140 fd->insertMember(md); 03141 } 03142 } 03143 03144 //printf("unrelated function %d `%s' `%s' `%s'\n", 03145 // root->parent->section,root->type.data(),rname.data(),root->args.data()); 03146 } 03147 else 03148 { 03149 Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data()); 03150 } 03151 } 03152 else if (rname.isEmpty()) 03153 { 03154 warn(root->fileName,root->startLine, 03155 "Warning: Illegal member name found." 03156 ); 03157 } 03158 03159 rootNav->releaseEntry(); 03160 } 03161 RECURSE_ENTRYTREE(buildFunctionList,rootNav); 03162 } 03163 03164 //---------------------------------------------------------------------- 03165 03166 static void findFriends() 03167 { 03168 //printf("findFriends()\n"); 03169 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); 03170 MemberName *fn; 03171 for (;(fn=fnli.current());++fnli) // for each global function name 03172 { 03173 //printf("Function name=`%s'\n",fn->memberName()); 03174 MemberName *mn; 03175 if ((mn=Doxygen::memberNameSDict->find(fn->memberName()))) 03176 { // there are members with the same name 03177 //printf("Function name is also a member name\n"); 03178 MemberNameIterator fni(*fn); 03179 MemberDef *fmd; 03180 for (;(fmd=fni.current());++fni) // for each function with that name 03181 { 03182 MemberNameIterator mni(*mn); 03183 MemberDef *mmd; 03184 for (;(mmd=mni.current());++mni) // for each member with that name 03185 { 03186 //printf("Checking for matching arguments 03187 // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n", 03188 // mmd->isRelated(),mmd->isFriend(),mmd->isFunction()); 03189 LockingPtr<ArgumentList> mmdAl = mmd->argumentList(); 03190 LockingPtr<ArgumentList> fmdAl = fmd->argumentList(); 03191 if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) && 03192 matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(), 03193 fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(), 03194 TRUE 03195 ) 03196 03197 ) // if the member is related and the arguments match then the 03198 // function is actually a friend. 03199 { 03200 mergeArguments(mmdAl.pointer(),fmdAl.pointer()); 03201 if (!fmd->documentation().isEmpty()) 03202 { 03203 mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine()); 03204 } 03205 else if (!mmd->documentation().isEmpty()) 03206 { 03207 fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine()); 03208 } 03209 if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty()) 03210 { 03211 mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine()); 03212 } 03213 else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty()) 03214 { 03215 fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine()); 03216 } 03217 if (!fmd->inbodyDocumentation().isEmpty()) 03218 { 03219 mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine()); 03220 } 03221 else if (!mmd->inbodyDocumentation().isEmpty()) 03222 { 03223 fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine()); 03224 } 03225 //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine()); 03226 if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1) 03227 { 03228 mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine()); 03229 mmd->setBodyDef(fmd->getBodyDef()); 03230 //mmd->setBodyMember(fmd); 03231 } 03232 else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1) 03233 { 03234 fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine()); 03235 fmd->setBodyDef(mmd->getBodyDef()); 03236 //fmd->setBodyMember(mmd); 03237 } 03238 mmd->setDocsForDefinition(fmd->isDocsForDefinition()); 03239 03240 mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph()); 03241 mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph()); 03242 fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph()); 03243 fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph()); 03244 } 03245 } 03246 } 03247 } 03248 } 03249 } 03250 03251 //---------------------------------------------------------------------- 03252 03253 static void transferArgumentDocumentation(ArgumentList *decAl,ArgumentList *defAl) 03254 { 03255 if (decAl && defAl) 03256 { 03257 ArgumentListIterator decAli(*decAl); 03258 ArgumentListIterator defAli(*defAl); 03259 Argument *decA,*defA; 03260 for (decAli.toFirst(),defAli.toFirst(); 03261 (decA=decAli.current()) && (defA=defAli.current()); 03262 ++decAli,++defAli) 03263 { 03264 //printf("Argument decA->name=%s (doc=%s) defA->name=%s (doc=%s)\n", 03265 // decA->name.data(),decA->docs.data(), 03266 // defA->name.data(),defA->docs.data() 03267 // ); 03268 if (decA->docs.isEmpty() && !defA->docs.isEmpty()) 03269 { 03270 decA->docs = defA->docs.copy(); 03271 } 03272 else if (defA->docs.isEmpty() && !decA->docs.isEmpty()) 03273 { 03274 defA->docs = decA->docs.copy(); 03275 } 03276 } 03277 } 03278 } 03279 03280 static void transferFunctionDocumentation() 03281 { 03282 //printf("transferFunctionDocumentation()\n"); 03283 03284 // find matching function declaration and definitions. 03285 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); 03286 MemberName *mn; 03287 for (;(mn=mnli.current());++mnli) 03288 { 03289 //printf("memberName=%s count=%d\n",mn->memberName(),mn->count()); 03290 MemberDef *mdef=0,*mdec=0; 03291 MemberNameIterator mni1(*mn); 03292 /* find a matching function declaration and definition for this function */ 03293 for (;(mdec=mni1.current());++mni1) 03294 { 03295 if (mdec->isPrototype() || 03296 (mdec->isVariable() && mdec->isExternal()) 03297 ) 03298 { 03299 MemberNameIterator mni2(*mn); 03300 for (;(mdef=mni2.current());++mni2) 03301 { 03302 if ( 03303 (mdef->isFunction() && !mdef->isStatic() && !mdef->isPrototype()) || 03304 (mdef->isVariable() && !mdef->isExternal() && !mdef->isStatic()) 03305 ) 03306 { 03307 //printf("mdef=(%p,%s) mdec=(%p,%s)\n", 03308 // mdef, mdef ? mdef->name().data() : "", 03309 // mdec, mdec ? mdec->name().data() : ""); 03310 03311 LockingPtr<ArgumentList> mdefAl = mdef->argumentList(); 03312 LockingPtr<ArgumentList> mdecAl = mdec->argumentList(); 03313 if (matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(), 03314 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(), 03315 TRUE 03316 ) 03317 ) /* match found */ 03318 { 03319 //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n", 03320 // mn->memberName(), 03321 // mdef->getFileDef()->name().data(),mdef->documentation().data(), 03322 // mdec->getFileDef()->name().data(),mdec->documentation().data() 03323 // ); 03324 03325 // first merge argument documentation 03326 transferArgumentDocumentation(mdecAl.pointer(),mdefAl.pointer()); 03327 03328 /* copy documentation between function definition and declaration */ 03329 if (!mdec->briefDescription().isEmpty()) 03330 { 03331 mdef->setBriefDescription(mdec->briefDescription(),mdec->briefFile(),mdec->briefLine()); 03332 } 03333 else if (!mdef->briefDescription().isEmpty()) 03334 { 03335 mdec->setBriefDescription(mdef->briefDescription(),mdef->briefFile(),mdef->briefLine()); 03336 } 03337 if (!mdef->documentation().isEmpty()) 03338 { 03339 //printf("transfering docs mdef->mdec (%s->%s)\n",mdef->argsString(),mdec->argsString()); 03340 mdec->setDocumentation(mdef->documentation(),mdef->docFile(),mdef->docLine()); 03341 mdec->setDocsForDefinition(mdef->isDocsForDefinition()); 03342 if (mdefAl!=0) 03343 { 03344 ArgumentList *mdefAlComb = new ArgumentList; 03345 stringToArgumentList(mdef->argsString(),mdefAlComb); 03346 transferArgumentDocumentation(mdefAl.pointer(),mdefAlComb); 03347 mdec->setArgumentList(mdefAlComb); 03348 } 03349 } 03350 else if (!mdec->documentation().isEmpty()) 03351 { 03352 //printf("transfering docs mdec->mdef (%s->%s)\n",mdec->argsString(),mdef->argsString()); 03353 mdef->setDocumentation(mdec->documentation(),mdec->docFile(),mdec->docLine()); 03354 mdef->setDocsForDefinition(mdec->isDocsForDefinition()); 03355 if (mdecAl!=0) 03356 { 03357 ArgumentList *mdecAlComb = new ArgumentList; 03358 stringToArgumentList(mdec->argsString(),mdecAlComb); 03359 transferArgumentDocumentation(mdecAl.pointer(),mdecAlComb); 03360 mdef->setDeclArgumentList(mdecAlComb); 03361 } 03362 } 03363 if (!mdef->inbodyDocumentation().isEmpty()) 03364 { 03365 mdec->setInbodyDocumentation(mdef->inbodyDocumentation(),mdef->inbodyFile(),mdef->inbodyLine()); 03366 } 03367 else if (!mdec->inbodyDocumentation().isEmpty()) 03368 { 03369 mdef->setInbodyDocumentation(mdec->inbodyDocumentation(),mdec->inbodyFile(),mdec->inbodyLine()); 03370 } 03371 if (mdec->getStartBodyLine()!=-1 && mdef->getStartBodyLine()==-1) 03372 { 03373 //printf("body mdec->mdef %d-%d\n",mdec->getStartBodyLine(),mdef->getEndBodyLine()); 03374 mdef->setBodySegment(mdec->getStartBodyLine(),mdec->getEndBodyLine()); 03375 mdef->setBodyDef(mdec->getBodyDef()); 03376 //mdef->setBodyMember(mdec); 03377 } 03378 else if (mdef->getStartBodyLine()!=-1 && mdec->getStartBodyLine()==-1) 03379 { 03380 //printf("body mdef->mdec %d-%d\n",mdef->getStartBodyLine(),mdec->getEndBodyLine()); 03381 mdec->setBodySegment(mdef->getStartBodyLine(),mdef->getEndBodyLine()); 03382 mdec->setBodyDef(mdef->getBodyDef()); 03383 //mdec->setBodyMember(mdef); 03384 } 03385 mdec->mergeMemberSpecifiers(mdef->getMemberSpecifiers()); 03386 mdef->mergeMemberSpecifiers(mdec->getMemberSpecifiers()); 03387 03388 03389 // copy group info. 03390 if (mdec->getGroupDef()==0 && mdef->getGroupDef()!=0) 03391 { 03392 mdec->setGroupDef(mdef->getGroupDef(), 03393 mdef->getGroupPri(), 03394 mdef->docFile(), 03395 mdef->docLine(), 03396 mdef->hasDocumentation(), 03397 mdef 03398 ); 03399 } 03400 else if (mdef->getGroupDef()==0 && mdec->getGroupDef()!=0) 03401 { 03402 mdef->setGroupDef(mdec->getGroupDef(), 03403 mdec->getGroupPri(), 03404 mdec->docFile(), 03405 mdec->docLine(), 03406 mdec->hasDocumentation(), 03407 mdec 03408 ); 03409 } 03410 03411 03412 mdec->mergeRefItems(mdef); 03413 mdef->mergeRefItems(mdec); 03414 03415 mdef->setMemberDeclaration(mdec); 03416 mdec->setMemberDefinition(mdef); 03417 03418 mdef->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph()); 03419 mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph()); 03420 mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph()); 03421 mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph()); 03422 } 03423 } 03424 } 03425 } 03426 } 03427 } 03428 } 03429 03430 //---------------------------------------------------------------------- 03431 03432 static void transferFunctionReferences() 03433 { 03434 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); 03435 MemberName *mn; 03436 for (;(mn=mnli.current());++mnli) 03437 { 03438 MemberDef *md,*mdef=0,*mdec=0; 03439 MemberNameIterator mni(*mn); 03440 /* find a matching function declaration and definition for this function */ 03441 for (;(md=mni.current());++mni) 03442 { 03443 if (md->isPrototype()) 03444 mdec=md; 03445 else if (md->isVariable() && md->isExternal()) 03446 mdec=md; 03447 03448 if (md->isFunction() && !md->isStatic() && !md->isPrototype()) 03449 mdef=md; 03450 else if (md->isVariable() && !md->isExternal() && !md->isStatic()) 03451 mdef=md; 03452 } 03453 if (mdef && mdec) 03454 { 03455 LockingPtr<ArgumentList> mdefAl = mdef->argumentList(); 03456 LockingPtr<ArgumentList> mdecAl = mdec->argumentList(); 03457 if ( 03458 matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(), 03459 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(), 03460 TRUE 03461 ) 03462 ) /* match found */ 03463 { 03464 LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers(); 03465 LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers(); 03466 if (defDict!=0) 03467 { 03468 MemberSDict::Iterator msdi(*defDict); 03469 MemberDef *rmd; 03470 for (msdi.toFirst();(rmd=msdi.current());++msdi) 03471 { 03472 if (decDict==0 || decDict->find(rmd->name())==0) 03473 { 03474 mdec->addSourceReferences(rmd); 03475 } 03476 } 03477 } 03478 if (decDict!=0) 03479 { 03480 MemberSDict::Iterator msdi(*decDict); 03481 MemberDef *rmd; 03482 for (msdi.toFirst();(rmd=msdi.current());++msdi) 03483 { 03484 if (defDict==0 || defDict->find(rmd->name())==0) 03485 { 03486 mdef->addSourceReferences(rmd); 03487 } 03488 } 03489 } 03490 03491 defDict = mdef->getReferencedByMembers(); 03492 decDict = mdec->getReferencedByMembers(); 03493 if (defDict!=0) 03494 { 03495 MemberSDict::Iterator msdi(*defDict); 03496 MemberDef *rmd; 03497 for (msdi.toFirst();(rmd=msdi.current());++msdi) 03498 { 03499 if (decDict==0 || decDict->find(rmd->name())==0) 03500 { 03501 mdec->addSourceReferencedBy(rmd); 03502 } 03503 } 03504 } 03505 if (decDict!=0) 03506 { 03507 MemberSDict::Iterator msdi(*decDict); 03508 MemberDef *rmd; 03509 for (msdi.toFirst();(rmd=msdi.current());++msdi) 03510 { 03511 if (defDict==0 || defDict->find(rmd->name())==0) 03512 { 03513 mdef->addSourceReferencedBy(rmd); 03514 } 03515 } 03516 } 03517 } 03518 } 03519 } 03520 } 03521 03522 //---------------------------------------------------------------------- 03523 03524 static void transferRelatedFunctionDocumentation() 03525 { 03526 // find match between function declaration and definition for 03527 // related functions 03528 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); 03529 MemberName *mn; 03530 for (mnli.toFirst();(mn=mnli.current());++mnli) 03531 { 03532 MemberDef *md; 03533 MemberNameIterator mni(*mn); 03534 /* find a matching function declaration and definition for this function */ 03535 for (mni.toFirst();(md=mni.current());++mni) // for each global function 03536 { 03537 //printf(" Function `%s'\n",md->name().data()); 03538 MemberName *rmn; 03539 if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name 03540 { 03541 //printf(" Member name found\n"); 03542 MemberDef *rmd; 03543 MemberNameIterator rmni(*rmn); 03544 for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name 03545 { 03546 LockingPtr<ArgumentList> mdAl = md->argumentList(); 03547 LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); 03548 //printf(" Member found: related=`%d'\n",rmd->isRelated()); 03549 if (rmd->isRelated() && // related function 03550 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(), 03551 rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), 03552 TRUE 03553 ) 03554 ) 03555 { 03556 //printf(" Found related member `%s'\n",md->name().data()); 03557 if (rmd->relatedAlso()) 03558 md->setRelatedAlso(rmd->relatedAlso()); 03559 else 03560 md->makeRelated(); 03561 } 03562 } 03563 } 03564 } 03565 } 03566 } 03567 03568 //---------------------------------------------------------------------- 03569 03575 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name) 03576 { 03577 QDict<int> *templateNames = new QDict<int>(17); 03578 templateNames->setAutoDelete(TRUE); 03579 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*"); 03580 if (templateArguments) 03581 { 03582 ArgumentListIterator ali(*templateArguments); 03583 Argument *arg; 03584 int count=0; 03585 for (ali.toFirst();(arg=ali.current());++ali,count++) 03586 { 03587 int i,p=0,l; 03588 while ((i=re.match(name,p,&l))!=-1) 03589 { 03590 QCString n = name.mid(i,l); 03591 if (n==arg->name) 03592 { 03593 if (templateNames->find(n)==0) 03594 { 03595 templateNames->insert(n,new int(count)); 03596 } 03597 } 03598 p=i+l; 03599 } 03600 } 03601 } 03602 return templateNames; 03603 } 03604 03608 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name) 03609 { 03610 FileDef *fd=cd->getFileDef(); 03611 ClassDef *result=0; 03612 if (context && cd!=context) 03613 { 03614 result = getResolvedClass(context,0,name,0,0,TRUE,TRUE); 03615 } 03616 if (result==0) 03617 { 03618 result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE); 03619 } 03620 //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n", 03621 // name.data(), 03622 // context ? context->name().data() : "<none>", 03623 // cd ? cd->name().data() : "<none>", 03624 // result ? result->name().data() : "<none>", 03625 // Doxygen::classSDict.find(name) 03626 // ); 03627 return result; 03628 } 03629 03630 enum FindBaseClassRelation_Mode 03631 { 03632 TemplateInstances, 03633 DocumentedOnly, 03634 Undocumented 03635 }; 03636 03637 static bool findClassRelation( 03638 EntryNav *rootNav, 03639 Definition *context, 03640 ClassDef *cd, 03641 BaseInfo *bi, 03642 QDict<int> *templateNames, 03643 /*bool insertUndocumented*/ 03644 FindBaseClassRelation_Mode mode, 03645 bool isArtificial 03646 ); 03647 03648 03649 static void findUsedClassesForClass(EntryNav *rootNav, 03650 Definition *context, 03651 ClassDef *masterCd, 03652 ClassDef *instanceCd, 03653 bool isArtificial, 03654 ArgumentList *actualArgs=0, 03655 QDict<int> *templateNames=0 03656 ) 03657 { 03658 masterCd->visited=TRUE; 03659 ArgumentList *formalArgs = masterCd->templateArguments(); 03660 if (masterCd->memberNameInfoSDict()) 03661 { 03662 MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict()); 03663 MemberNameInfo *mni; 03664 for (;(mni=mnili.current());++mnili) 03665 { 03666 MemberNameInfoIterator mnii(*mni); 03667 MemberInfo *mi; 03668 for (mnii.toFirst();(mi=mnii.current());++mnii) 03669 { 03670 MemberDef *md=mi->memberDef; 03671 if (md->isVariable()) // for each member variable in this class 03672 { 03673 //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data()); 03674 QCString type=removeRedundantWhiteSpace(md->typeString()); 03675 QCString typedefValue = resolveTypeDef(masterCd,type); 03676 if (!typedefValue.isEmpty()) 03677 { 03678 type = typedefValue; 03679 } 03680 int pos=0; 03681 QCString usedClassName; 03682 QCString templSpec; 03683 bool found=FALSE; 03684 // the type can contain template variables, replace them if present 03685 if (actualArgs) 03686 { 03687 type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs); 03688 } 03689 03690 //printf(" template substitution gives=%s\n",type.data()); 03691 while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1) 03692 { 03693 // find the type (if any) that matches usedClassName 03694 ClassDef *typeCd = getResolvedClass(masterCd, 03695 masterCd->getFileDef(), 03696 usedClassName, 03697 0,0, 03698 FALSE,TRUE 03699 ); 03700 //printf("====> usedClassName=%s -> typeCd=%s\n", 03701 // usedClassName.data(),typeCd?typeCd->name().data():"<none>"); 03702 if (typeCd) 03703 { 03704 usedClassName = typeCd->name(); 03705 } 03706 03707 int sp=usedClassName.find('<'); 03708 if (sp==-1) sp=0; 03709 int si=usedClassName.findRev("::",sp); 03710 if (si!=-1) 03711 { 03712 // replace any namespace aliases 03713 replaceNamespaceAliases(usedClassName,si); 03714 } 03715 // add any template arguments to the class 03716 QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec); 03717 //printf(" usedName=%s\n",usedName.data()); 03718 03719 bool delTempNames=FALSE; 03720 if (templateNames==0) 03721 { 03722 templateNames = getTemplateArgumentsInName(formalArgs,usedName); 03723 delTempNames=TRUE; 03724 } 03725 BaseInfo bi(usedName,Public,Normal); 03726 findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial); 03727 03728 if (masterCd->templateArguments()) 03729 { 03730 ArgumentListIterator ali(*masterCd->templateArguments()); 03731 Argument *arg; 03732 int count=0; 03733 for (ali.toFirst();(arg=ali.current());++ali,++count) 03734 { 03735 if (arg->name==usedName) // type is a template argument 03736 { 03737 found=TRUE; 03738 Debug::print(Debug::Classes,0," New used class `%s'\n", usedName.data()); 03739 03740 ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName); 03741 if (usedCd==0) 03742 { 03743 usedCd = new ClassDef( 03744 masterCd->getDefFileName(),masterCd->getDefLine(), 03745 usedName,ClassDef::Class); 03746 //printf("making %s a template argument!!!\n",usedCd->name().data()); 03747 usedCd->makeTemplateArgument(); 03748 usedCd->setUsedOnly(TRUE); 03749 Doxygen::hiddenClasses->append(usedName,usedCd); 03750 } 03751 if (usedCd) 03752 { 03753 if (isArtificial) usedCd->setArtificial(TRUE); 03754 Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", usedCd->name().data()); 03755 instanceCd->addUsedClass(usedCd,md->name()); 03756 usedCd->addUsedByClass(instanceCd,md->name()); 03757 } 03758 } 03759 } 03760 } 03761 03762 if (!found) 03763 { 03764 ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName); 03765 //printf("Looking for used class %s: result=%s master=%s\n", 03766 // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>"); 03767 03768 if (usedCd) 03769 { 03770 found=TRUE; 03771 Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", usedCd->name().data()); 03772 instanceCd->addUsedClass(usedCd,md->name()); // class exists 03773 usedCd->addUsedByClass(instanceCd,md->name()); 03774 } 03775 } 03776 if (delTempNames) 03777 { 03778 delete templateNames; 03779 templateNames=0; 03780 } 03781 } 03782 if (!found && !type.isEmpty()) // used class is not documented in any scope 03783 { 03784 ClassDef *usedCd = Doxygen::hiddenClasses->find(type); 03785 if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS")) 03786 { 03787 if (type.right(2)=="(*") // type is a function pointer 03788 { 03789 type+=md->argsString(); 03790 } 03791 Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data()); 03792 usedCd = new ClassDef( 03793 masterCd->getDefFileName(),masterCd->getDefLine(), 03794 type,ClassDef::Class); 03795 usedCd->setUsedOnly(TRUE); 03796 Doxygen::hiddenClasses->append(type,usedCd); 03797 } 03798 if (usedCd) 03799 { 03800 if (isArtificial) usedCd->setArtificial(TRUE); 03801 Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", usedCd->name().data()); 03802 instanceCd->addUsedClass(usedCd,md->name()); 03803 usedCd->addUsedByClass(instanceCd,md->name()); 03804 } 03805 } 03806 } 03807 } 03808 } 03809 } 03810 else 03811 { 03812 //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd); 03813 } 03814 } 03815 03816 static void findBaseClassesForClass( 03817 EntryNav *rootNav, 03818 Definition *context, 03819 ClassDef *masterCd, 03820 ClassDef *instanceCd, 03821 FindBaseClassRelation_Mode mode, 03822 bool isArtificial, 03823 ArgumentList *actualArgs=0, 03824 QDict<int> *templateNames=0 03825 ) 03826 { 03827 Entry *root = rootNav->entry(); 03828 //if (masterCd->visited) return; 03829 masterCd->visited=TRUE; 03830 // The base class could ofcouse also be a non-nested class 03831 ArgumentList *formalArgs = masterCd->templateArguments(); 03832 QListIterator<BaseInfo> bii(*root->extends); 03833 BaseInfo *bi=0; 03834 for (bii.toFirst();(bi=bii.current());++bii) 03835 { 03836 //printf("masterCd=%s bi->name=%s #actualArgs=%d\n", 03837 // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1); 03838 bool delTempNames=FALSE; 03839 if (templateNames==0) 03840 { 03841 templateNames = getTemplateArgumentsInName(formalArgs,bi->name); 03842 delTempNames=TRUE; 03843 } 03844 BaseInfo tbi(bi->name,bi->prot,bi->virt); 03845 if (actualArgs) // substitute the formal template arguments of the base class 03846 { 03847 tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs); 03848 } 03849 //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data()); 03850 03851 if (mode==DocumentedOnly) 03852 { 03853 // find a documented base class in the correct scope 03854 if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial)) 03855 { 03856 if (!Config_getBool("HIDE_UNDOC_RELATIONS")) 03857 { 03858 // no documented base class -> try to find an undocumented one 03859 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,isArtificial); 03860 } 03861 } 03862 } 03863 else if (mode==TemplateInstances) 03864 { 03865 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial); 03866 } 03867 if (delTempNames) 03868 { 03869 delete templateNames; 03870 templateNames=0; 03871 } 03872 } 03873 } 03874 03875 //---------------------------------------------------------------------- 03876 03877 static bool findTemplateInstanceRelation(Entry *root, 03878 Definition *context, 03879 ClassDef *templateClass,const QCString &templSpec, 03880 QDict<int> *templateNames, 03881 bool isArtificial) 03882 { 03883 Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n", 03884 templateClass->name().data(),templSpec.data()); 03885 //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=", 03886 // templateClass->name().data(),templSpec.data()); 03887 //if (templateNames) 03888 //{ 03889 // QDictIterator<int> qdi(*templateNames); 03890 // int *tempArgIndex; 03891 // for (;(tempArgIndex=qdi.current());++qdi) 03892 // { 03893 // printf("(%s->%d) ",qdi.currentKey().data(),*tempArgIndex); 03894 // } 03895 //} 03896 //printf("\n"); 03897 03898 bool existingClass = (templSpec==tempArgListToString(templateClass->templateArguments())); 03899 if (existingClass) return TRUE; 03900 03901 bool freshInstance=FALSE; 03902 ClassDef *instanceClass = templateClass->insertTemplateInstance( 03903 root->fileName,root->startLine,templSpec,freshInstance); 03904 if (isArtificial) instanceClass->setArtificial(TRUE); 03905 instanceClass->setIsObjectiveC(root->objc); 03906 03907 if (freshInstance) 03908 { 03909 Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",instanceClass->name().data()); 03910 Doxygen::classSDict->append(instanceClass->name(),instanceClass); 03911 instanceClass->setTemplateBaseClassNames(templateNames); 03912 03913 // search for new template instances caused by base classes of 03914 // instanceClass 03915 EntryNav *templateRootNav = classEntries.find(templateClass->name()); 03916 if (templateRootNav) 03917 { 03918 bool unloadNeeded=FALSE; 03919 Entry *templateRoot = templateRootNav->entry(); 03920 if (templateRoot==0) // not yet loaded 03921 { 03922 templateRootNav->loadEntry(g_storage); 03923 templateRoot = templateRootNav->entry(); 03924 ASSERT(templateRoot!=0); // now it should really be loaded 03925 unloadNeeded=TRUE; 03926 } 03927 03928 Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n", 03929 templateRoot->name.data(),templSpec.data()); 03930 ArgumentList *templArgs = new ArgumentList; 03931 stringToArgumentList(templSpec,templArgs); 03932 findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass, 03933 TemplateInstances,isArtificial,templArgs,templateNames); 03934 03935 findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass, 03936 isArtificial,templArgs,templateNames); 03937 delete templArgs; 03938 03939 if (unloadNeeded) // still cleanup to do 03940 { 03941 templateRootNav->releaseEntry(); 03942 } 03943 } 03944 else 03945 { 03946 Debug::print(Debug::Classes,0," no template root entry found!\n"); 03947 // TODO: what happened if we get here? 03948 } 03949 03950 //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data()); 03951 //ArgumentList *tl = templateClass->templateArguments(); 03952 } 03953 else 03954 { 03955 Debug::print(Debug::Classes,0," instance already exists!\n"); 03956 } 03957 return TRUE; 03958 } 03959 03960 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name) 03961 { 03962 QCString n=name; 03963 int index=n.find('<'); 03964 if (index!=-1) 03965 { 03966 n=n.left(index); 03967 } 03968 bool result = rightScopeMatch(scope,n); 03969 return result; 03970 } 03971 03985 static int findEndOfTemplate(const QCString &s,int startPos) 03986 { 03987 // locate end of template 03988 int e=startPos; 03989 int brCount=1; 03990 int roundCount=0; 03991 int len = s.length(); 03992 bool insideString=FALSE; 03993 bool insideChar=FALSE; 03994 char pc = 0; 03995 while (e<len && brCount!=0) 03996 { 03997 char c=s.at(e); 03998 switch(c) 03999 { 04000 case '<': 04001 if (!insideString && !insideChar) 04002 { 04003 if (e<len-1 && s.at(e+1)=='<') 04004 e++; 04005 else if (roundCount==0) 04006 brCount++; 04007 } 04008 break; 04009 case '>': 04010 if (!insideString && !insideChar) 04011 { 04012 if (e<len-1 && s.at(e+1)=='>') 04013 e++; 04014 else if (roundCount==0) 04015 brCount--; 04016 } 04017 break; 04018 case '(': 04019 if (!insideString && !insideChar) 04020 roundCount++; 04021 break; 04022 case ')': 04023 if (!insideString && !insideChar) 04024 roundCount--; 04025 break; 04026 case '"': 04027 if (!insideChar) 04028 { 04029 if (insideString && pc!='\\') 04030 insideString=FALSE; 04031 else 04032 insideString=TRUE; 04033 } 04034 break; 04035 case '\'': 04036 if (!insideString) 04037 { 04038 if (insideChar && pc!='\\') 04039 insideChar=FALSE; 04040 else 04041 insideChar=TRUE; 04042 } 04043 break; 04044 } 04045 pc = c; 04046 e++; 04047 } 04048 return brCount==0 ? e : -1; 04049 } 04050 04051 static bool findClassRelation( 04052 EntryNav *rootNav, 04053 Definition *context, 04054 ClassDef *cd, 04055 BaseInfo *bi, 04056 QDict<int> *templateNames, 04057 FindBaseClassRelation_Mode mode, 04058 bool isArtificial 04059 ) 04060 { 04061 //printf("findClassRelation(class=%s base=%s templateNames=", 04062 // cd->name().data(),bi->name.data()); 04063 //if (templateNames) 04064 //{ 04065 // QDictIterator<int> qdi(*templateNames); 04066 // int *tempArgIndex; 04067 // for (;(tempArgIndex=qdi.current());++qdi) 04068 // { 04069 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex); 04070 // } 04071 //} 04072 //printf("\n"); 04073 04074 Entry *root = rootNav->entry(); 04075 04076 QCString biName=bi->name; 04077 bool explicitGlobalScope=FALSE; 04078 if (biName.left(2)=="::") // explicit global scope 04079 { 04080 biName=biName.right(biName.length()-2); 04081 explicitGlobalScope=TRUE; 04082 } 04083 //printf("biName=`%s'\n",biName.data()); 04084 04085 EntryNav *parentNode=rootNav->parent(); 04086 bool lastParent=FALSE; 04087 do // for each parent scope, starting with the largest scope 04088 // (in case of nested classes) 04089 { 04090 QCString scopeName= parentNode ? parentNode->name().data() : ""; 04091 int scopeOffset=explicitGlobalScope ? 0 : scopeName.length(); 04092 do // try all parent scope prefixes, starting with the largest scope 04093 { 04094 //printf("scopePrefix=`%s' biName=`%s'\n", 04095 // scopeName.left(scopeOffset).data(),biName.data()); 04096 04097 QCString baseClassName=biName; 04098 if (scopeOffset>0) 04099 { 04100 baseClassName.prepend(scopeName.left(scopeOffset)+"::"); 04101 } 04102 baseClassName=stripTemplateSpecifiersFromScope 04103 (removeRedundantWhiteSpace(baseClassName)); 04104 MemberDef *baseClassTypeDef=0; 04105 QCString templSpec; 04106 ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? 0 : cd, 04107 cd->getFileDef(), 04108 baseClassName, 04109 &baseClassTypeDef, 04110 &templSpec, 04111 mode==Undocumented, 04112 TRUE 04113 ); 04114 //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n", 04115 // baseClassName.data(),baseClass,cd,explicitGlobalScope); 04116 //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n", 04117 // cd ? cd->name().data():"<none>", 04118 // baseClassName.data(), 04119 // baseClass?baseClass->name().data():"<none>", 04120 // templSpec.data() 04121 // ); 04122 //if (baseClassName.left(root->name.length())!=root->name || 04123 // baseClassName.at(root->name.length())!='<' 04124 // ) // Check for base class with the same name. 04125 // // If found then look in the outer scope for a match 04126 // // and prevent recursion. 04127 if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope) 04128 { 04129 Debug::print( 04130 Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n", 04131 baseClassName.data(), 04132 rootNav->name().data(), 04133 (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"), 04134 (bi->virt==Normal)?"normal":"virtual", 04135 templSpec.data() 04136 ); 04137 04138 int i=baseClassName.find('<'); 04139 int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i); 04140 if (si==-1) si=0; 04141 if (baseClass==0 && i!=-1) 04142 // base class has template specifiers 04143 { 04144 // TODO: here we should try to find the correct template specialization 04145 // but for now, we only look for the unspecializated base class. 04146 int e=findEndOfTemplate(baseClassName,i+1); 04147 if (e!=-1) // end of template was found at e 04148 { 04149 templSpec=baseClassName.mid(i,e-i); 04150 baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e); 04151 baseClass=getResolvedClass(cd, 04152 cd->getFileDef(), 04153 baseClassName, 04154 &baseClassTypeDef, 04155 0, //&templSpec, 04156 mode==Undocumented, 04157 TRUE 04158 ); 04159 //printf("baseClass=%p -> baseClass=%s templSpec=%s\n", 04160 // baseClass,baseClassName.data(),templSpec.data()); 04161 } 04162 } 04163 else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also 04164 // know it is a template, so see if 04165 // we can also link to the explicit 04166 // instance (for instance if a class 04167 // derived from a template argument) 04168 { 04169 ClassDef *templClass=getClass(baseClass->name()+templSpec); 04170 if (templClass) 04171 { 04172 // use the template instance instead of the template base. 04173 baseClass = templClass; 04174 templSpec.resize(0); 04175 } 04176 } 04177 04178 //printf("cd=%p baseClass=%p\n",cd,baseClass); 04179 bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances); 04180 if (!found && si!=-1) 04181 { 04182 QCString tmpTemplSpec; 04183 // replace any namespace aliases 04184 replaceNamespaceAliases(baseClassName,si); 04185 baseClass=getResolvedClass(cd, 04186 cd->getFileDef(), 04187 baseClassName, 04188 &baseClassTypeDef, 04189 &tmpTemplSpec, 04190 mode==Undocumented, 04191 TRUE 04192 ); 04193 found=baseClass!=0 && baseClass!=cd; 04194 if (found) templSpec = tmpTemplSpec; 04195 } 04196 04197 //printf("root->name=%s biName=%s baseClassName=%s\n", 04198 // root->name.data(),biName.data(),baseClassName.data()); 04199 04200 //FileDef *fd=cd->getFileDef(); 04201 //NamespaceDef *nd=cd->getNamespaceDef(); 04202 if (!found) 04203 { 04204 baseClass=findClassWithinClassContext(context,cd,baseClassName); 04205 //printf("findClassWithinClassContext(%s,%s)=%p\n", 04206 // cd->name().data(),baseClassName.data(),baseClass); 04207 found = baseClass!=0 && baseClass!=cd; 04208 04209 } 04210 bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0; 04211 // make templSpec canonical 04212 templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec); 04213 04214 if (found) 04215 { 04216 Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data()); 04217 // add base class to this class 04218 04219 // if templSpec is not empty then we should "instantiate" 04220 // the template baseClass. A new ClassDef should be created 04221 // to represent the instance. To be able to add the (instantiated) 04222 // members and documentation of a template class 04223 // (inserted in that template class at a later stage), 04224 // the template should know about its instances. 04225 // the instantiation process, should be done in a recursive way, 04226 // since instantiating a template may introduce new inheritance 04227 // relations. 04228 if (!templSpec.isEmpty() && mode==TemplateInstances) 04229 { 04230 //printf(" => findTemplateInstanceRelation\n"); 04231 findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial); 04232 } 04233 else if (mode==DocumentedOnly || mode==Undocumented) 04234 { 04235 //printf(" => insert base class\n"); 04236 QCString usedName; 04237 if (baseClassTypeDef) 04238 { 04239 usedName=biName; 04240 //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data()); 04241 } 04242 if (Config_getBool("SIP_SUPPORT")) bi->prot=Public; 04243 cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec); 04244 // add this class as super class to the base class 04245 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec); 04246 } 04247 return TRUE; 04248 } 04249 else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument)) 04250 { 04251 Debug::print(Debug::Classes,0, 04252 " New undocumented base class `%s' baseClassName=%s\n", 04253 biName.data(),baseClassName.data() 04254 ); 04255 baseClass=0; 04256 if (isATemplateArgument) 04257 { 04258 baseClass=Doxygen::hiddenClasses->find(baseClassName); 04259 if (baseClass==0) 04260 { 04261 baseClass=new ClassDef(root->fileName,root->startLine, 04262 baseClassName,ClassDef::Class); 04263 Doxygen::hiddenClasses->append(baseClassName,baseClass); 04264 if (isArtificial) baseClass->setArtificial(TRUE); 04265 } 04266 } 04267 else 04268 { 04269 baseClass=Doxygen::classSDict->find(baseClassName); 04270 //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n", 04271 // baseClassName.data(),baseClass,biName.data(),templSpec.data()); 04272 if (baseClass==0) 04273 { 04274 baseClass=new ClassDef(root->fileName,root->startLine, 04275 baseClassName,ClassDef::Class); 04276 Doxygen::classSDict->append(baseClassName,baseClass); 04277 if (isArtificial) baseClass->setArtificial(TRUE); 04278 } 04279 } 04280 // add base class to this class 04281 cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec); 04282 // add this class as super class to the base class 04283 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec); 04284 // the undocumented base was found in this file 04285 baseClass->insertUsedFile(root->fileName); 04286 baseClass->setOuterScope(Doxygen::globalScope); 04287 return TRUE; 04288 } 04289 else 04290 { 04291 Debug::print(Debug::Classes,0," Base class `%s' not found\n",biName.data()); 04292 } 04293 } 04294 else 04295 { 04296 if (mode!=TemplateInstances) 04297 { 04298 warn(root->fileName,root->startLine, 04299 "Detected potential recursive class relation " 04300 "between class %s and base class %s!\n", 04301 root->name.data(),baseClassName.data() 04302 ); 04303 } 04304 // for mode==TemplateInstance this case is quite common and 04305 // indicates a relation between a template class and a template 04306 // instance with the same name. 04307 } 04308 if (scopeOffset==0) 04309 { 04310 scopeOffset=-1; 04311 } 04312 else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1) 04313 { 04314 scopeOffset=0; 04315 } 04316 //printf("new scopeOffset=`%d'",scopeOffset); 04317 } while (scopeOffset>=0); 04318 04319 if (parentNode==0) 04320 { 04321 lastParent=TRUE; 04322 } 04323 else 04324 { 04325 parentNode=parentNode->parent(); 04326 } 04327 } while (lastParent); 04328 04329 return FALSE; 04330 } 04331 04332 //---------------------------------------------------------------------- 04333 // Computes the base and super classes for each class in the tree 04334 04335 static bool isClassSection(EntryNav *rootNav) 04336 { 04337 if ( !rootNav->name().isEmpty() ) 04338 { 04339 if (rootNav->section() & Entry::COMPOUND_MASK) 04340 // is it a compound (class, struct, union, interface ...) 04341 { 04342 return TRUE; 04343 } 04344 else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) 04345 // is it a documentation block with inheritance info. 04346 { 04347 rootNav->loadEntry(g_storage); 04348 Entry *root = rootNav->entry(); 04349 bool extends = root->extends->count()>0; 04350 rootNav->releaseEntry(); 04351 if (extends) return TRUE; 04352 } 04353 } 04354 return FALSE; 04355 } 04356 04357 04360 static void findClassEntries(EntryNav *rootNav) 04361 { 04362 if (isClassSection(rootNav)) 04363 { 04364 classEntries.insert(rootNav->name(),rootNav); 04365 } 04366 RECURSE_ENTRYTREE(findClassEntries,rootNav); 04367 } 04368 04374 static void findInheritedTemplateInstances() 04375 { 04376 ClassSDict::Iterator cli(*Doxygen::classSDict); 04377 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; 04378 QDictIterator<EntryNav> edi(classEntries); 04379 EntryNav *rootNav; 04380 for (;(rootNav=edi.current());++edi) 04381 { 04382 ClassDef *cd; 04383 // strip any annonymous scopes first 04384 QCString bName=stripAnonymousNamespaceScope(rootNav->name()); 04385 bName=stripTemplateSpecifiersFromScope(bName); 04386 Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",bName.data()); 04387 if ((cd=getClass(bName))) 04388 { 04389 rootNav->loadEntry(g_storage); 04390 //printf("Class %s %d\n",cd->name().data(),root->extends->count()); 04391 findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE); 04392 rootNav->releaseEntry(); 04393 } 04394 } 04395 } 04396 04397 static void findUsedTemplateInstances() 04398 { 04399 ClassSDict::Iterator cli(*Doxygen::classSDict); 04400 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; 04401 QDictIterator<EntryNav> edi(classEntries); 04402 EntryNav *rootNav; 04403 for (;(rootNav=edi.current());++edi) 04404 { 04405 ClassDef *cd; 04406 // strip any annonymous scopes first 04407 QCString bName=stripAnonymousNamespaceScope(rootNav->name()); 04408 bName=stripTemplateSpecifiersFromScope(bName); 04409 Debug::print(Debug::Classes,0," Usage: Class %s : \n",bName.data()); 04410 if ((cd=getClass(bName))) 04411 { 04412 rootNav->loadEntry(g_storage); 04413 findUsedClassesForClass(rootNav,cd,cd,cd,TRUE); 04414 rootNav->releaseEntry(); 04415 } 04416 } 04417 } 04418 04419 static void computeClassRelations() 04420 { 04421 ClassSDict::Iterator cli(*Doxygen::classSDict); 04422 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; 04423 QDictIterator<EntryNav> edi(classEntries); 04424 EntryNav *rootNav; 04425 for (;(rootNav=edi.current());++edi) 04426 { 04427 ClassDef *cd; 04428 04429 rootNav->loadEntry(g_storage); 04430 Entry *root = rootNav->entry(); 04431 04432 // strip any annonymous scopes first 04433 QCString bName=stripAnonymousNamespaceScope(rootNav->name()); 04434 bName=stripTemplateSpecifiersFromScope(bName); 04435 Debug::print(Debug::Classes,0," Relations: Class %s : \n",bName.data()); 04436 if ((cd=getClass(bName))) 04437 { 04438 findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE); 04439 } 04440 if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && 04441 bName.right(2)!="::") 04442 { 04443 if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name 04444 (guessSection(root->fileName)==Entry::HEADER_SEC || 04445 Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file 04446 (root->protection!=Private || Config_getBool("EXTRACT_PRIVATE")) && // hidden by protection 04447 !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible 04448 ) 04449 warn_undoc( 04450 root->fileName,root->startLine, 04451 "Warning: Compound %s is not documented.", 04452 root->name.data() 04453 ); 04454 } 04455 04456 rootNav->releaseEntry(); 04457 } 04458 } 04459 04460 static void computeTemplateClassRelations() 04461 { 04462 QDictIterator<EntryNav> edi(classEntries); 04463 EntryNav *rootNav; 04464 for (;(rootNav=edi.current());++edi) 04465 { 04466 rootNav->loadEntry(g_storage); 04467 Entry *root = rootNav->entry(); 04468 04469 QCString bName=stripAnonymousNamespaceScope(root->name); 04470 bName=stripTemplateSpecifiersFromScope(bName); 04471 ClassDef *cd=getClass(bName); 04472 // strip any annonymous scopes first 04473 QDict<ClassDef> *templInstances = 0; 04474 if (cd && (templInstances=cd->getTemplateInstances())) 04475 { 04476 Debug::print(Debug::Classes,0," Template class %s : \n",cd->name().data()); 04477 QDictIterator<ClassDef> tdi(*templInstances); 04478 ClassDef *tcd; 04479 for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance 04480 { 04481 Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data()); 04482 QCString templSpec = tdi.currentKey(); 04483 ArgumentList *templArgs = new ArgumentList; 04484 stringToArgumentList(templSpec,templArgs); 04485 QList<BaseInfo> *baseList=root->extends; 04486 BaseInfo *bi=baseList->first(); 04487 while (bi) // for each base class of the template 04488 { 04489 // check if the base class is a template argument 04490 BaseInfo tbi(bi->name,bi->prot,bi->virt); 04491 ArgumentList *tl = cd->templateArguments(); 04492 if (tl) 04493 { 04494 QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames(); 04495 QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name); 04496 // for each template name that we inherit from we need to 04497 // substitute the formal with the actual arguments 04498 QDict<int> *actualTemplateNames = new QDict<int>(17); 04499 actualTemplateNames->setAutoDelete(TRUE); 04500 QDictIterator<int> qdi(*templateNames); 04501 for (qdi.toFirst();qdi.current();++qdi) 04502 { 04503 int templIndex = *qdi.current(); 04504 Argument *actArg = 0; 04505 if (templIndex<(int)templArgs->count()) 04506 { 04507 actArg=templArgs->at(templIndex); 04508 } 04509 if (actArg!=0 && 04510 baseClassNames!=0 && 04511 baseClassNames->find(actArg->type)!=0 && 04512 actualTemplateNames->find(actArg->type)==0 04513 ) 04514 { 04515 actualTemplateNames->insert(actArg->type,new int(templIndex)); 04516 } 04517 } 04518 delete templateNames; 04519 04520 tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs); 04521 // find a documented base class in the correct scope 04522 if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE)) 04523 { 04524 // no documented base class -> try to find an undocumented one 04525 findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE); 04526 } 04527 delete actualTemplateNames; 04528 } 04529 bi=baseList->next(); 04530 } 04531 delete templArgs; 04532 } // class has no base classes 04533 } 04534 04535 rootNav->releaseEntry(); 04536 } 04537 } 04538 04539 //----------------------------------------------------------------------- 04540 // compute the references (anchors in HTML) for each function in the file 04541 04542 static void computeMemberReferences() 04543 { 04544 ClassSDict::Iterator cli(*Doxygen::classSDict); 04545 ClassDef *cd=0; 04546 for (cli.toFirst();(cd=cli.current());++cli) 04547 { 04548 cd->computeAnchors(); 04549 } 04550 FileName *fn=Doxygen::inputNameList->first(); 04551 while (fn) 04552 { 04553 FileDef *fd=fn->first(); 04554 while (fd) 04555 { 04556 fd->computeAnchors(); 04557 fd=fn->next(); 04558 } 04559 fn=Doxygen::inputNameList->next(); 04560 } 04561 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); 04562 NamespaceDef *nd=0; 04563 for (nli.toFirst();(nd=nli.current());++nli) 04564 { 04565 nd->computeAnchors(); 04566 } 04567 GroupSDict::Iterator gli(*Doxygen::groupSDict); 04568 GroupDef *gd; 04569 for (gli.toFirst();(gd=gli.current());++gli) 04570 { 04571 gd->computeAnchors(); 04572 } 04573 } 04574 04575 //---------------------------------------------------------------------- 04576 04577 static void addListReferences() 04578 { 04579 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); 04580 MemberName *mn=0; 04581 for (mnli.toFirst();(mn=mnli.current());++mnli) 04582 { 04583 MemberNameIterator mni(*mn); 04584 MemberDef *md=0; 04585 for (mni.toFirst();(md=mni.current());++mni) 04586 { 04587 md->visited=FALSE; 04588 } 04589 } 04590 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); 04591 for (fnli.toFirst();(mn=fnli.current());++fnli) 04592 { 04593 MemberNameIterator mni(*mn); 04594 MemberDef *md=0; 04595 for (mni.toFirst();(md=mni.current());++mni) 04596 { 04597 md->visited=FALSE; 04598 } 04599 } 04600 04601 ClassSDict::Iterator cli(*Doxygen::classSDict); 04602 ClassDef *cd=0; 04603 for (cli.toFirst();(cd=cli.current());++cli) 04604 { 04605 cd->addListReferences(); 04606 } 04607 FileName *fn=Doxygen::inputNameList->first(); 04608 while (fn) 04609 { 04610 FileDef *fd=fn->first(); 04611 while (fd) 04612 { 04613 fd->addListReferences(); 04614 fd=fn->next(); 04615 } 04616 fn=Doxygen::inputNameList->next(); 04617 } 04618 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); 04619 NamespaceDef *nd=0; 04620 for (nli.toFirst();(nd=nli.current());++nli) 04621 { 04622 nd->addListReferences(); 04623 } 04624 GroupSDict::Iterator gli(*Doxygen::groupSDict); 04625 GroupDef *gd; 04626 for (gli.toFirst();(gd=gli.current());++gli) 04627 { 04628 gd->addListReferences(); 04629 } 04630 PageSDict::Iterator pdi(*Doxygen::pageSDict); 04631 PageDef *pd=0; 04632 for (pdi.toFirst();(pd=pdi.current());++pdi) 04633 { 04634 QCString name = pd->name(); 04635 if (pd->getGroupDef()) 04636 { 04637 name = pd->getGroupDef()->getOutputFileBase().copy(); 04638 } 04639 { 04640 LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems(); 04641 addRefItem(xrefItems.pointer(), 04642 theTranslator->trPage(TRUE,TRUE), 04643 name,pd->title()); 04644 } 04645 } 04646 } 04647 04648 //---------------------------------------------------------------------- 04649 // Copy the documentation in entry `root' to member definition `md' and 04650 // set the function declaration of the member to `funcDecl'. If the boolean 04651 // over_load is set the standard overload text is added. 04652 04653 static void addMemberDocs(EntryNav *rootNav, 04654 MemberDef *md, const char *funcDecl, 04655 ArgumentList *al, 04656 bool over_load, 04657 NamespaceSDict * 04658 ) 04659 { 04660 Entry *root = rootNav->entry(); 04661 //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n", 04662 // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec); 04663 QCString fDecl=funcDecl; 04664 // strip extern specifier 04665 fDecl.stripPrefix("extern "); 04666 md->setDefinition(fDecl); 04667 md->enableCallGraph(root->callGraph); 04668 md->enableCallerGraph(root->callerGraph); 04669 ClassDef *cd=md->getClassDef(); 04670 NamespaceDef *nd=md->getNamespaceDef(); 04671 QCString fullName; 04672 if (cd) 04673 fullName = cd->name(); 04674 else if (nd) 04675 fullName = nd->name(); 04676 04677 if (!fullName.isEmpty()) fullName+="::"; 04678 fullName+=md->name(); 04679 FileDef *rfd=rootNav->fileDef(); 04680 04681 // TODO determine scope based on root not md 04682 Definition *rscope = md->getOuterScope(); 04683 04684 LockingPtr<ArgumentList> mdAl = md->argumentList(); 04685 if (al) 04686 { 04687 //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty()); 04688 mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty()); 04689 } 04690 else 04691 { 04692 if ( 04693 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(), 04694 rscope,rfd,root->argList, 04695 TRUE 04696 ) 04697 ) 04698 { 04699 //printf("merging arguments (2)\n"); 04700 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty()); 04701 } 04702 } 04703 if (over_load) // the \overload keyword was used 04704 { 04705 QCString doc=getOverloadDocs(); 04706 if (!root->doc.isEmpty()) 04707 { 04708 doc+="<p>"; 04709 doc+=root->doc; 04710 } 04711 md->setDocumentation(doc,root->docFile,root->docLine); 04712 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 04713 md->setDocsForDefinition(!root->proto); 04714 } 04715 else 04716 { 04717 //printf("Adding docs md->docs=`%s' root->docs=`%s'!\n", 04718 // md->documentation().data(),root->doc.data()); 04719 // documentation outside a compound overrides the documentation inside it 04720 04721 #if 0 04722 if ( /* !md->isStatic() && !root->stat && do not replace doc of a static */ 04723 ( 04724 md->documentation().isEmpty() || /* no docs yet */ 04725 (rootNav->parent()->name().isEmpty() && /* or overwrite prototype docs */ 04726 !root->proto && md->isPrototype() /* with member definition docs */ 04727 ) 04728 ) && !root->doc.isEmpty() 04729 ) 04730 #endif 04731 { 04732 //printf("overwrite!\n"); 04733 md->setDocumentation(root->doc,root->docFile,root->docLine); 04734 md->setDocsForDefinition(!root->proto); 04735 } 04736 04737 //printf("Adding brief md->brief=`%s' root->brief=`%s'!\n", 04738 // md->briefDescription().data(),root->brief.data()); 04739 // brief descriptions inside a compound override the documentation 04740 // outside it 04741 #if 0 04742 if ( /* !md->isStatic() && !root->stat && do not replace doc of static */ 04743 ( 04744 md->briefDescription().isEmpty() || /* no docs yet */ 04745 !rootNav->parent()->name().isEmpty() /* member of a class */ 04746 ) && !root->brief.isEmpty() 04747 ) 04748 #endif 04749 { 04750 //printf("overwrite!\n"); 04751 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 04752 } 04753 04754 if ( 04755 (md->inbodyDocumentation().isEmpty() || 04756 !rootNav->parent()->name().isEmpty() 04757 ) && !root->inbodyDocs.isEmpty() 04758 ) 04759 { 04760 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 04761 } 04762 } 04763 04764 //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n", 04765 // md->initializer().data(),md->initializer().isEmpty(), 04766 // root->initializer.data(),root->initializer.isEmpty() 04767 // ); 04768 if (md->initializer().isEmpty() && !root->initializer.isEmpty()) 04769 { 04770 //printf("setInitializer\n"); 04771 md->setInitializer(root->initializer); 04772 } 04773 04774 md->setMaxInitLines(root->initLines); 04775 04776 if (rfd) 04777 { 04778 04779 if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) 04780 // || (md->isVariable() && !root->explicitExternal) 04781 ) 04782 { 04783 //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine); 04784 md->setBodySegment(root->bodyLine,root->endBodyLine); 04785 md->setBodyDef(rfd); 04786 } 04787 04788 md->setRefItems(root->sli); 04789 } 04790 04791 md->enableCallGraph(md->hasCallGraph() || root->callGraph); 04792 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph); 04793 04794 md->mergeMemberSpecifiers(root->spec); 04795 md->addSectionsToDefinition(root->anchors); 04796 addMemberToGroups(root,md); 04797 if (cd) cd->insertUsedFile(root->fileName); 04798 //printf("root->mGrpId=%d\n",root->mGrpId); 04799 if (root->mGrpId!=-1) 04800 { 04801 if (md->getMemberGroupId()!=-1) 04802 { 04803 if (md->getMemberGroupId()!=root->mGrpId) 04804 { 04805 warn( 04806 root->fileName,root->startLine, 04807 "Warning: member %s belongs to two different groups. The second " 04808 "one found here will be ignored.", 04809 md->name().data() 04810 ); 04811 } 04812 } 04813 else // set group id 04814 { 04815 //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data()); 04816 md->setMemberGroupId(root->mGrpId); 04817 } 04818 } 04819 } 04820 04821 //---------------------------------------------------------------------- 04822 // find a class definition given the scope name and (optionally) a 04823 // template list specifier 04824 04825 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd, 04826 const char *scopeName) 04827 { 04828 ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE); 04829 return tcd; 04830 } 04831 04832 04833 //---------------------------------------------------------------------- 04834 // Adds the documentation contained in `root' to a global function 04835 // with name `name' and argument list `args' (for overloading) and 04836 // function declaration `decl' to the corresponding member definition. 04837 04838 static bool findGlobalMember(EntryNav *rootNav, 04839 const QCString &namespaceName, 04840 const char *name, 04841 const char *tempArg, 04842 const char *, 04843 const char *decl) 04844 { 04845 Entry *root = rootNav->entry(); 04846 Debug::print(Debug::FindMembers,0, 04847 "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n", 04848 namespaceName.data(),name,tempArg,decl); 04849 QCString n=name; 04850 if (n.isEmpty()) return FALSE; 04851 if (n.find("::")!=-1) return FALSE; // skip undefined class members 04852 MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary 04853 if (mn==0) 04854 { 04855 mn=Doxygen::functionNameSDict->find(n); // try without template arguments 04856 } 04857 if (mn) // function name defined 04858 { 04859 Debug::print(Debug::FindMembers,0,"3. Found function scope\n"); 04860 //int count=0; 04861 MemberNameIterator mni(*mn); 04862 MemberDef *md; 04863 bool found=FALSE; 04864 for (mni.toFirst();(md=mni.current()) && !found;++mni) 04865 { 04866 NamespaceDef *nd=md->getNamespaceDef(); 04867 04868 //printf("Namespace namespaceName=%s nd=%s\n", 04869 // namespaceName.data(),nd ? nd->name().data() : "<none>"); 04870 04871 FileDef *fd=rootNav->fileDef(); 04872 //printf("File %s\n",fd ? fd->name().data() : "<none>"); 04873 NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0; 04874 //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0; 04875 //printf("NamespaceList %p\n",nl); 04876 04877 // search in the list of namespaces that are imported via a 04878 // using declaration 04879 bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0; 04880 04881 if ((namespaceName.isEmpty() && nd==0) || // not in a namespace 04882 (nd && nd->name()==namespaceName) || // or in the same namespace 04883 viaUsingDirective // member in `using' namespace 04884 ) 04885 { 04886 Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n", 04887 md->name().data(),namespaceName.data()); 04888 QCString nsName = nd ? nd->name().data() : ""; 04889 04890 NamespaceDef *rnd = 0; 04891 if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName); 04892 04893 LockingPtr<ArgumentList> mdAl = md->argumentList(); 04894 bool matching= 04895 (mdAl==0 && root->argList->count()==0) || 04896 md->isVariable() || md->isTypedef() || /* in case of function pointers */ 04897 matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(), 04898 rnd ? rnd : Doxygen::globalScope,fd,root->argList, 04899 FALSE); 04900 04901 //printf("%s<->%s\n", 04902 // argListToString(md->argumentList()).data(), 04903 // argListToString(root->argList).data()); 04904 04905 // for static members we also check if the comment block was found in 04906 // the same file. This is needed because static members with the same 04907 // name can be in different files. Thus it would be wrong to just 04908 // put the comment block at the first syntactically matching member. 04909 if (matching && md->isStatic() && 04910 md->getDefFileName()!=root->fileName && 04911 mn->count()>1) 04912 { 04913 matching = FALSE; 04914 } 04915 04916 if (matching) // add docs to the member 04917 { 04918 Debug::print(Debug::FindMembers,0,"5. Match found\n"); 04919 addMemberDocs(rootNav,md,decl,root->argList,FALSE); 04920 found=TRUE; 04921 } 04922 } 04923 } 04924 if (!found && !root->relatesDup) // no match 04925 { 04926 QCString fullFuncDecl=decl; 04927 if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE); 04928 warn(root->fileName,root->startLine, 04929 "Warning: no matching file member found for \n%s",fullFuncDecl.data()); 04930 if (mn->count()>0) 04931 { 04932 warn_cont("Possible candidates:\n"); 04933 for (mni.toFirst();(md=mni.current());++mni) 04934 { 04935 warn_cont(" %s\n",md->declaration()); 04936 } 04937 } 04938 } 04939 } 04940 else // got docs for an undefined member! 04941 { 04942 if (root->type!="friend class" && 04943 root->type!="friend struct" && 04944 root->type!="friend union") 04945 { 04946 warn(root->fileName,root->startLine, 04947 "Warning: documented function `%s' was not declared or defined.",decl 04948 ); 04949 } 04950 } 04951 return TRUE; 04952 } 04953 04954 static bool isSpecialization( 04955 const QList<ArgumentList> &srcTempArgLists, 04956 const QList<ArgumentList> &dstTempArgLists 04957 ) 04958 { 04959 QListIterator<ArgumentList> srclali(srcTempArgLists); 04960 QListIterator<ArgumentList> dstlali(dstTempArgLists); 04961 for (;srclali.current();++srclali,++dstlali) 04962 { 04963 ArgumentList *sal = srclali.current(); 04964 ArgumentList *dal = dstlali.current(); 04965 if (!(sal && dal && sal->count()==dal->count())) return TRUE; 04966 } 04967 return FALSE; 04968 } 04969 04970 04971 static QCString substituteTemplatesInString( 04972 const QList<ArgumentList> &srcTempArgLists, 04973 const QList<ArgumentList> &dstTempArgLists, 04974 ArgumentList *funcTempArgList, // can be used to match template specializations 04975 const QCString &src 04976 ) 04977 { 04978 QCString dst; 04979 QRegExp re(idMask); 04980 //printf("type=%s\n",sa->type.data()); 04981 04982 int i,p=0,l; 04983 while ((i=re.match(src,p,&l))!=-1) // for each word in srcType 04984 { 04985 bool found=FALSE; 04986 dst+=src.mid(p,i-p); 04987 QCString name=src.mid(i,l); 04988 04989 QListIterator<ArgumentList> srclali(srcTempArgLists); 04990 QListIterator<ArgumentList> dstlali(dstTempArgLists); 04991 for (;srclali.current() && !found;++srclali,++dstlali) 04992 { 04993 ArgumentListIterator tsali(*srclali.current()); 04994 ArgumentListIterator tdali(*dstlali.current()); 04995 Argument *tsa =0,*tda=0, *fa=0; 04996 if (funcTempArgList) 04997 { 04998 fa=funcTempArgList->first(); 04999 } 05000 05001 for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali) 05002 { 05003 tda = tdali.current(); 05004 if (name==tsa->name) 05005 { 05006 if (tda) 05007 { 05008 name=tda->name; // substitute 05009 found=TRUE; 05010 } 05011 else if (fa) 05012 { 05013 name=fa->type; 05014 found=TRUE; 05015 } 05016 } 05017 if (tda) 05018 ++tdali; 05019 else if (fa) 05020 fa=funcTempArgList->next(); 05021 } 05022 } 05023 dst+=name; 05024 p=i+l; 05025 } 05026 dst+=src.right(src.length()-p); 05027 return dst; 05028 } 05029 05030 static void substituteTemplatesInArgList( 05031 const QList<ArgumentList> &srcTempArgLists, 05032 const QList<ArgumentList> &dstTempArgLists, 05033 ArgumentList *src, 05034 ArgumentList *dst, 05035 ArgumentList *funcTempArgs = 0 05036 ) 05037 { 05038 ArgumentListIterator sali(*src); 05039 Argument *sa=0; 05040 Argument *da=dst->first(); 05041 05042 for (sali.toFirst();(sa=sali.current());++sali) // for each member argument 05043 { 05044 QCString dstType = substituteTemplatesInString( 05045 srcTempArgLists,dstTempArgLists,funcTempArgs, 05046 sa->type); 05047 QCString dstArray = substituteTemplatesInString( 05048 srcTempArgLists,dstTempArgLists,funcTempArgs, 05049 sa->array); 05050 if (da==0) 05051 { 05052 da=new Argument(*sa); 05053 dst->append(da); 05054 da->type=dstType; 05055 da->array=dstArray; 05056 da=0; 05057 } 05058 else 05059 { 05060 da->type=dstType; 05061 da->type=dstArray; 05062 da=dst->next(); 05063 } 05064 } 05065 dst->constSpecifier = src->constSpecifier; 05066 dst->volatileSpecifier = src->volatileSpecifier; 05067 dst->pureSpecifier = src->pureSpecifier; 05068 //printf("substituteTemplatesInArgList: replacing %s with %s\n", 05069 // argListToString(src).data(),argListToString(dst).data()); 05070 } 05071 05072 05073 05083 static void findMember(EntryNav *rootNav, 05084 QCString funcDecl, 05085 bool overloaded, 05086 bool isFunc 05087 ) 05088 { 05089 Entry *root = rootNav->entry(); 05090 05091 Debug::print(Debug::FindMembers,0, 05092 "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d," 05093 "isFunc=%d mGrpId=%d tArgList=%p (#=%d) " 05094 "spec=%d isObjC=%d\n", 05095 root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId, 05096 root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0, 05097 root->spec,root->objc 05098 ); 05099 05100 QCString scopeName; 05101 QCString className; 05102 QCString namespaceName; 05103 QCString funcType; 05104 QCString funcName; 05105 QCString funcArgs; 05106 QCString funcTempList; 05107 QCString exceptions; 05108 QCString funcSpec; 05109 bool isRelated=FALSE; 05110 bool isFriend=FALSE; 05111 bool done; 05112 do 05113 { 05114 done=TRUE; 05115 if (funcDecl.stripPrefix("friend ")) // treat friends as related members 05116 { 05117 isFriend=TRUE; 05118 done=FALSE; 05119 } 05120 if (funcDecl.stripPrefix("inline ")) 05121 { 05122 root->spec|=Entry::Inline; 05123 done=FALSE; 05124 } 05125 if (funcDecl.stripPrefix("explicit ")) 05126 { 05127 root->spec|=Entry::Explicit; 05128 done=FALSE; 05129 } 05130 if (funcDecl.stripPrefix("mutable ")) 05131 { 05132 root->spec|=Entry::Mutable; 05133 done=FALSE; 05134 } 05135 if (funcDecl.stripPrefix("virtual ")) 05136 { 05137 done=FALSE; 05138 } 05139 } while (!done); 05140 05141 // delete any ; from the function declaration 05142 int sep; 05143 while ((sep=funcDecl.find(';'))!=-1) 05144 { 05145 funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace(); 05146 } 05147 05148 // make sure the first character is a space to simplify searching. 05149 if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" "); 05150 05151 // remove some superfluous spaces 05152 funcDecl= substitute( 05153 substitute( 05154 substitute(funcDecl,"~ ","~"), 05155 ":: ","::" 05156 ), 05157 " ::","::" 05158 ).stripWhiteSpace(); 05159 05160 //printf("funcDecl=`%s'\n",funcDecl.data()); 05161 if (isFriend && funcDecl.left(6)=="class ") 05162 { 05163 //printf("friend class\n"); 05164 funcDecl=funcDecl.right(funcDecl.length()-6); 05165 funcName = funcDecl.copy(); 05166 } 05167 else if (isFriend && funcDecl.left(7)=="struct ") 05168 { 05169 funcDecl=funcDecl.right(funcDecl.length()-7); 05170 funcName = funcDecl.copy(); 05171 } 05172 else 05173 { 05174 // extract information from the declarations 05175 parseFuncDecl(funcDecl,root->objc,scopeName,funcType,funcName, 05176 funcArgs,funcTempList,exceptions 05177 ); 05178 } 05179 //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n", 05180 // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data()); 05181 05182 // the class name can also be a namespace name, we decide this later. 05183 // if a related class name is specified and the class name could 05184 // not be derived from the function declaration, then use the 05185 // related field. 05186 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n", 05187 // scopeName.data(),className.data(),namespaceName.data()); 05188 if (!root->relates.isEmpty()) 05189 { // related member, prefix user specified scope 05190 isRelated=TRUE; 05191 if (getClass(root->relates)==0 && !scopeName.isEmpty()) 05192 scopeName= mergeScopes(scopeName,root->relates); 05193 else 05194 scopeName = root->relates; 05195 } 05196 05197 if (root->relates.isEmpty() && rootNav->parent() && 05198 ((rootNav->parent()->section()&Entry::SCOPE_MASK) || 05199 (rootNav->parent()->section()==Entry::OBJCIMPL_SEC) 05200 ) && 05201 !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName 05202 // with the scope in which it was found 05203 { 05204 QCString joinedName = rootNav->parent()->name()+"::"+scopeName; 05205 if (!scopeName.isEmpty() && 05206 (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName))) 05207 { 05208 scopeName = joinedName; 05209 } 05210 else 05211 { 05212 scopeName = mergeScopes(rootNav->parent()->name(),scopeName); 05213 } 05214 } 05215 else // see if we can prefix a namespace or class that is used from the file 05216 { 05217 FileDef *fd=rootNav->fileDef(); 05218 if (fd) 05219 { 05220 NamespaceSDict *fnl = fd->getUsedNamespaces(); 05221 if (fnl) 05222 { 05223 QCString joinedName; 05224 NamespaceDef *fnd; 05225 NamespaceSDict::Iterator nsdi(*fnl); 05226 for (nsdi.toFirst();(fnd=nsdi.current());++nsdi) 05227 { 05228 joinedName = fnd->name()+"::"+scopeName; 05229 if (Doxygen::namespaceSDict->find(joinedName)) 05230 { 05231 scopeName=joinedName; 05232 break; 05233 } 05234 } 05235 } 05236 } 05237 } 05238 scopeName=stripTemplateSpecifiersFromScope( 05239 removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); 05240 05241 // funcSpec contains the last template specifiers of the given scope. 05242 // If this method does not have any template arguments or they are 05243 // empty while funcSpec is not empty we assume this is a 05244 // specialization of a method. If not, we clear the funcSpec and treat 05245 // this as a normal method of a template class. 05246 if (!(root->tArgLists && 05247 root->tArgLists->count()>0 && 05248 root->tArgLists->first()->count()==0 05249 ) 05250 ) 05251 { 05252 funcSpec.resize(0); 05253 } 05254 05255 // split scope into a namespace and a class part 05256 extractNamespaceName(scopeName,className,namespaceName,TRUE); 05257 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n", 05258 // scopeName.data(),className.data(),namespaceName.data()); 05259 05260 namespaceName=removeAnonymousScopes(namespaceName); 05261 //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data()); 05262 // merge class and namespace scopes again 05263 scopeName.resize(0); 05264 if (!namespaceName.isEmpty()) 05265 { 05266 if (className.isEmpty()) 05267 { 05268 scopeName=namespaceName; 05269 } 05270 else if (!getClass(className)) // class name only exists in a namespace 05271 { 05272 scopeName=namespaceName+"::"+className; 05273 } 05274 else 05275 { 05276 scopeName=className; 05277 } 05278 } 05279 else if (!className.isEmpty()) 05280 { 05281 scopeName=className; 05282 } 05283 //printf("new scope=`%s'\n",scopeName.data()); 05284 05285 QCString tempScopeName=scopeName; 05286 ClassDef *cd=getClass(scopeName); 05287 if (cd) 05288 { 05289 if (root->tArgLists) root->tArgLists->first(); 05290 if (funcSpec.isEmpty()) 05291 { 05292 tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists); 05293 } 05294 else 05295 { 05296 tempScopeName=scopeName+funcSpec; 05297 } 05298 } 05299 //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n", 05300 // scopeName.data(),cd,root->tArgLists,tempScopeName.data()); 05301 05302 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); 05303 // rebuild the function declaration (needed to get the scope right). 05304 if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES")) 05305 { 05306 if (!funcType.isEmpty()) 05307 { 05308 if (isFunc) // a function -> we use argList for the arguments 05309 { 05310 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList; 05311 } 05312 else 05313 { 05314 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs; 05315 } 05316 } 05317 else 05318 { 05319 if (isFunc) // a function => we use argList for the arguments 05320 { 05321 funcDecl=tempScopeName+"::"+funcName+funcTempList; 05322 } 05323 else // variable => add `argument' list 05324 { 05325 funcDecl=tempScopeName+"::"+funcName+funcArgs; 05326 } 05327 } 05328 } 05329 else // build declaration without scope 05330 { 05331 if (!funcType.isEmpty()) // but with a type 05332 { 05333 if (isFunc) // function => omit argument list 05334 { 05335 funcDecl=funcType+" "+funcName+funcTempList; 05336 } 05337 else // variable => add `argument' list 05338 { 05339 funcDecl=funcType+" "+funcName+funcArgs; 05340 } 05341 } 05342 else // no type 05343 { 05344 if (isFunc) 05345 { 05346 funcDecl=funcName+funcTempList; 05347 } 05348 else 05349 { 05350 funcDecl=funcName+funcArgs; 05351 } 05352 } 05353 } 05354 05355 if (funcType=="template class" && !funcTempList.isEmpty()) 05356 return; // ignore explicit template instantiations 05357 05358 Debug::print(Debug::FindMembers,0, 05359 "findMember() Parse results:\n" 05360 " namespaceName=`%s'\n" 05361 " className=`%s`\n" 05362 " funcType=`%s'\n" 05363 " funcSpec=`%s'\n" 05364 " funcName=`%s'\n" 05365 " funcArgs=`%s'\n" 05366 " funcTempList=`%s'\n" 05367 " funcDecl=`%s'\n" 05368 " related=`%s'\n" 05369 " exceptions=`%s'\n" 05370 " isRelated=%d\n" 05371 " isFriend=%d\n" 05372 " isFunc=%d\n\n", 05373 namespaceName.data(),className.data(), 05374 funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(), 05375 funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isFriend, 05376 isFunc 05377 ); 05378 05379 MemberName *mn=0; 05380 if (!funcName.isEmpty()) // function name is valid 05381 { 05382 Debug::print(Debug::FindMembers,0, 05383 "1. funcName=`%s'\n",funcName.data()); 05384 if (funcName.left(9)=="operator ") // strip class scope from cast operator 05385 { 05386 funcName = substitute(funcName,className+"::",""); 05387 } 05388 if (!funcTempList.isEmpty()) // try with member specialization 05389 { 05390 mn=Doxygen::memberNameSDict->find(funcName+funcTempList); 05391 } 05392 if (mn==0) // try without specialization 05393 { 05394 mn=Doxygen::memberNameSDict->find(funcName); 05395 } 05396 if (!isRelated && mn) // function name already found 05397 { 05398 Debug::print(Debug::FindMembers,0, 05399 "2. member name exists (%d members with this name)\n",mn->count()); 05400 if (!className.isEmpty()) // class name is valid 05401 { 05402 if (funcSpec.isEmpty()) // not a member specialization 05403 { 05404 int count=0; 05405 int noMatchCount=0; 05406 MemberNameIterator mni(*mn); 05407 MemberDef *md; 05408 bool memFound=FALSE; 05409 for (mni.toFirst();!memFound && (md=mni.current());++mni) 05410 { 05411 ClassDef *cd=md->getClassDef(); 05412 Debug::print(Debug::FindMembers,0, 05413 "3. member definition found, " 05414 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n", 05415 scopeName.data(),cd ? cd->name().data() : "<none>", 05416 md->argsString(), 05417 root->fileName.data()); 05418 //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data()); 05419 FileDef *fd=rootNav->fileDef(); 05420 NamespaceDef *nd=0; 05421 if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName); 05422 05423 ClassDef *tcd=findClassDefinition(fd,nd,scopeName); 05424 if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName) 05425 { 05426 // don't be fooled by anonymous scopes 05427 tcd=cd; 05428 } 05429 //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n", 05430 // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd); 05431 05432 if (cd && tcd==cd) // member's classes match 05433 { 05434 Debug::print(Debug::FindMembers,0, 05435 "4. class definition %s found\n",cd->name().data()); 05436 05437 // get the template parameter lists found at the member declaration 05438 QList<ArgumentList> declTemplArgs; 05439 cd->getTemplateParameterLists(declTemplArgs); 05440 LockingPtr<ArgumentList> templAl = md->templateArguments(); 05441 if (templAl!=0) 05442 { 05443 declTemplArgs.append(templAl.pointer()); 05444 } 05445 05446 // get the template parameter lists found at the member definition 05447 QList<ArgumentList> *defTemplArgs = root->tArgLists; 05448 //printf("defTemplArgs=%p\n",defTemplArgs); 05449 05450 // do we replace the decl argument lists with the def argument lists? 05451 bool substDone=FALSE; 05452 ArgumentList *argList=0; 05453 05454 /* substitute the occurrences of class template names in the 05455 * argument list before matching 05456 */ 05457 LockingPtr<ArgumentList> mdAl = md->argumentList(); 05458 if (declTemplArgs.count()>0 && defTemplArgs && 05459 declTemplArgs.count()==defTemplArgs->count() && 05460 mdAl.pointer() 05461 ) 05462 { 05463 /* the function definition has template arguments 05464 * and the class definition also has template arguments, so 05465 * we must substitute the template names of the class by that 05466 * of the function definition before matching. 05467 */ 05468 argList = new ArgumentList; 05469 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs, 05470 mdAl.pointer(),argList); 05471 05472 substDone=TRUE; 05473 } 05474 else /* no template arguments, compare argument lists directly */ 05475 { 05476 argList = mdAl.pointer(); 05477 } 05478 05479 Debug::print(Debug::FindMembers,0, 05480 "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n", 05481 argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(), 05482 className.data(),namespaceName.data() 05483 ); 05484 05485 bool matching= 05486 md->isVariable() || md->isTypedef() || // needed for function pointers 05487 (mdAl.pointer()==0 && root->argList->count()==0) || 05488 matchArguments2( 05489 md->getClassDef(),md->getFileDef(),argList, 05490 cd,fd,root->argList, 05491 TRUE); 05492 05493 Debug::print(Debug::FindMembers,0, 05494 "6. match results of matchArguments2 = %d\n",matching); 05495 05496 if (substDone) // found a new argument list 05497 { 05498 if (matching) // replace member's argument list 05499 { 05500 md->setDefinitionTemplateParameterLists(root->tArgLists); 05501 md->setArgumentList(argList); // new owner of the list => no delete 05502 } 05503 else // no match 05504 { 05505 if (!funcTempList.isEmpty() && 05506 isSpecialization(declTemplArgs,*defTemplArgs)) 05507 { 05508 // check if we are dealing with a partial template 05509 // specialization. In this case we add it to the class 05510 // even though the member arguments do not match. 05511 05512 // TODO: copy other aspects? 05513 root->protection=md->protection(); // copy protection level 05514 addMethodToClass(rootNav,cd,md->name(),isFriend); 05515 return; 05516 } 05517 delete argList; 05518 } 05519 } 05520 if (matching) 05521 { 05522 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */); 05523 count++; 05524 memFound=TRUE; 05525 } 05526 } 05527 else if (cd && cd!=tcd) // we did find a class with the same name as cd 05528 // but in a different namespace 05529 { 05530 noMatchCount++; 05531 } 05532 } 05533 if (count==0 && rootNav->parent() && 05534 rootNav->parent()->section()==Entry::OBJCIMPL_SEC) 05535 { 05536 goto localObjCMethod; 05537 } 05538 if (count==0 && !(isFriend && funcType=="class")) 05539 { 05540 int candidates=0; 05541 if (mn->count()>0) 05542 { 05543 //printf("Assume template class\n"); 05544 for (mni.toFirst();(md=mni.current());++mni) 05545 { 05546 ClassDef *cd=md->getClassDef(); 05547 //printf("cd->name()==%s className=%s\n",cd->name().data(),className.data()); 05548 if (cd!=0 && rightScopeMatch(cd->name(),className)) 05549 { 05550 LockingPtr<ArgumentList> templAl = md->templateArguments(); 05551 if (root->tArgLists && templAl!=0 && 05552 root->tArgLists->getLast()->count()<=templAl->count()) 05553 { 05554 addMethodToClass(rootNav,cd,md->name(),isFriend); 05555 return; 05556 } 05557 candidates++; 05558 } 05559 } 05560 } 05561 05562 warn(root->fileName,root->startLine, 05563 "Warning: no %smatching class member found for", 05564 noMatchCount>1 ? "uniquely " : "" 05565 ); 05566 05567 if (root->tArgLists) 05568 { 05569 QListIterator<ArgumentList> alli(*root->tArgLists); 05570 ArgumentList *al; 05571 for (;(al=alli.current());++alli) 05572 { 05573 warn_cont(" template %s\n",tempArgListToString(al).data()); 05574 } 05575 } 05576 QCString fullFuncDecl=funcDecl.copy(); 05577 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); 05578 05579 warn_cont(" %s\n",fullFuncDecl.data()); 05580 05581 if (candidates>0) 05582 { 05583 warn_cont("Possible candidates:\n"); 05584 for (mni.toFirst();(md=mni.current());++mni) 05585 { 05586 ClassDef *cd=md->getClassDef(); 05587 if (cd!=0 && rightScopeMatch(cd->name(),className)) 05588 { 05589 LockingPtr<ArgumentList> templAl = md->templateArguments(); 05590 if (templAl!=0) 05591 { 05592 warn_cont(" template %s\n",tempArgListToString(templAl.pointer()).data()); 05593 } 05594 warn_cont(" "); 05595 if (md->typeString()) 05596 { 05597 warn_cont("%s ",md->typeString()); 05598 } 05599 QCString qScope = cd->qualifiedNameWithTemplateParameters(); 05600 if (!qScope.isEmpty()) warn_cont("%s::%s",qScope.data(),md->name().data()); 05601 if (md->argsString()) warn_cont("%s",md->argsString()); 05602 if (noMatchCount>1) warn_cont(" at line %d of file %s",md->getDefLine(),md->getDefFileName().data()); 05603 warn_cont("\n"); 05604 } 05605 } 05606 } 05607 } 05608 } 05609 else if (cd) // member specialization 05610 { 05611 MemberDef::MemberType mtype=MemberDef::Function; 05612 ArgumentList *tArgList = new ArgumentList; 05613 // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists); 05614 MemberDef *md=new MemberDef( 05615 root->fileName,root->startLine, 05616 funcType,funcName,funcArgs,exceptions, 05617 root->protection,root->virt,root->stat,FALSE, 05618 mtype,tArgList,root->argList); 05619 //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data()); 05620 md->setTagInfo(rootNav->tagInfo()); 05621 md->setMemberClass(cd); 05622 md->setTemplateSpecialization(TRUE); 05623 md->setTypeConstraints(root->typeConstr); 05624 md->setDefinition(funcDecl); 05625 md->enableCallGraph(root->callGraph); 05626 md->enableCallerGraph(root->callerGraph); 05627 md->setDocumentation(root->doc,root->docFile,root->docLine); 05628 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 05629 md->setDocsForDefinition(!root->proto); 05630 md->setPrototype(root->proto); 05631 md->addSectionsToDefinition(root->anchors); 05632 md->setBodySegment(root->bodyLine,root->endBodyLine); 05633 FileDef *fd=rootNav->fileDef(); 05634 md->setBodyDef(fd); 05635 md->setMemberSpecifiers(root->spec); 05636 md->setMemberGroupId(root->mGrpId); 05637 mn->append(md); 05638 cd->insertMember(md); 05639 md->setRefItems(root->sli); 05640 delete tArgList; 05641 } 05642 else 05643 { 05644 //printf("*** Specialized member %s of unknown scope %s%s found!\n", 05645 // scopeName.data(),funcName.data(),funcArgs.data()); 05646 } 05647 } 05648 else if (overloaded) // check if the function belongs to only one class 05649 { 05650 // for unique overloaded member we allow the class to be 05651 // omitted, this is to be Qt compatable. Using this should 05652 // however be avoided, because it is error prone 05653 MemberNameIterator mni(*mn); 05654 MemberDef *md=mni.toFirst(); 05655 ASSERT(md); 05656 ClassDef *cd=md->getClassDef(); 05657 ASSERT(cd); 05658 QCString className=cd->name().copy(); 05659 ++mni; 05660 bool unique=TRUE; 05661 for (;(md=mni.current());++mni) 05662 { 05663 ClassDef *cd=md->getClassDef(); 05664 if (className!=cd->name()) unique=FALSE; 05665 } 05666 if (unique) 05667 { 05668 MemberDef::MemberType mtype; 05669 if (root->mtype==Signal) mtype=MemberDef::Signal; 05670 else if (root->mtype==Slot) mtype=MemberDef::Slot; 05671 else if (root->mtype==DCOP) mtype=MemberDef::DCOP; 05672 else mtype=MemberDef::Function; 05673 05674 // new overloaded member function 05675 ArgumentList *tArgList = 05676 getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists); 05677 //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data()); 05678 MemberDef *md=new MemberDef( 05679 root->fileName,root->startLine, 05680 funcType,funcName,funcArgs,exceptions, 05681 root->protection,root->virt,root->stat,TRUE, 05682 mtype,tArgList,root->argList); 05683 md->setTagInfo(rootNav->tagInfo()); 05684 md->setTypeConstraints(root->typeConstr); 05685 md->setMemberClass(cd); 05686 md->setDefinition(funcDecl); 05687 md->enableCallGraph(root->callGraph); 05688 md->enableCallerGraph(root->callerGraph); 05689 QCString doc=getOverloadDocs(); 05690 doc+="<p>"; 05691 doc+=root->doc; 05692 md->setDocumentation(doc,root->docFile,root->docLine); 05693 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 05694 md->setDocsForDefinition(!root->proto); 05695 md->setPrototype(root->proto); 05696 md->addSectionsToDefinition(root->anchors); 05697 md->setBodySegment(root->bodyLine,root->endBodyLine); 05698 FileDef *fd=rootNav->fileDef(); 05699 md->setBodyDef(fd); 05700 md->setMemberSpecifiers(root->spec); 05701 md->setMemberGroupId(root->mGrpId); 05702 mn->append(md); 05703 cd->insertMember(md); 05704 cd->insertUsedFile(root->fileName); 05705 md->setRefItems(root->sli); 05706 } 05707 } 05708 else // unrelated function with the same name as a member 05709 { 05710 if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl)) 05711 { 05712 QCString fullFuncDecl=funcDecl.copy(); 05713 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); 05714 warn(root->fileName,root->startLine, 05715 "Warning: Cannot determine class for function\n%s", 05716 fullFuncDecl.data() 05717 ); 05718 } 05719 } 05720 } 05721 else if (isRelated && !root->relates.isEmpty()) 05722 { 05723 Debug::print(Debug::FindMembers,0,"2. related function\n" 05724 " scopeName=%s className=%s\n",scopeName.data(),className.data()); 05725 if (className.isEmpty()) className=root->relates.copy(); 05726 ClassDef *cd; 05727 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); 05728 if ((cd=getClass(scopeName))) 05729 { 05730 bool newMember=TRUE; // assume we have a new member 05731 bool newMemberName=FALSE; 05732 bool isDefine=FALSE; 05733 { 05734 MemberName *mn = Doxygen::functionNameSDict->find(funcName); 05735 if (mn) 05736 { 05737 MemberDef *md = mn->first(); 05738 while (md && !isDefine) 05739 { 05740 isDefine = isDefine || md->isDefine(); 05741 md = mn->next(); 05742 } 05743 } 05744 } 05745 05746 FileDef *fd=rootNav->fileDef(); 05747 05748 if ((mn=Doxygen::memberNameSDict->find(funcName))==0) 05749 { 05750 mn=new MemberName(funcName); 05751 newMemberName=TRUE; // we create a new member name 05752 } 05753 else 05754 { 05755 MemberDef *rmd=mn->first(); 05756 while (rmd && newMember) // see if we got another member with matching arguments 05757 { 05758 LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); 05759 05760 newMember=newMember && 05761 !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), 05762 cd,fd,root->argList, 05763 TRUE); 05764 if (newMember) rmd=mn->next(); 05765 } 05766 if (!newMember && rmd) // member already exists as rmd -> add docs 05767 { 05768 //printf("addMemberDocs for related member %s\n",root->name.data()); 05769 //rmd->setMemberDefTemplateArguments(root->mtArgList); 05770 addMemberDocs(rootNav,rmd,funcDecl,0,overloaded); 05771 } 05772 } 05773 05774 if (newMember) // need to create a new member 05775 { 05776 MemberDef::MemberType mtype; 05777 if (isDefine) 05778 mtype=MemberDef::Define; 05779 else if (root->mtype==Signal) 05780 mtype=MemberDef::Signal; 05781 else if (root->mtype==Slot) 05782 mtype=MemberDef::Slot; 05783 else if (root->mtype==DCOP) 05784 mtype=MemberDef::DCOP; 05785 else 05786 mtype=MemberDef::Function; 05787 05788 //printf("New related name `%s' `%d'\n",funcName.data(), 05789 // root->argList ? (int)root->argList->count() : -1); 05790 05791 // new related (member) function 05792 #if 0 // removed as it doesn't handle related template functions correctly 05793 ArgumentList *tArgList = 05794 getTemplateArgumentsFromName(scopeName+"::"+funcName,root->tArgLists); 05795 MemberDef *md=new MemberDef( 05796 root->fileName,root->startLine, 05797 funcType,funcName,funcArgs,exceptions, 05798 root->protection,root->virt,root->stat,TRUE, 05799 mtype,tArgList,funcArgs.isEmpty() ? 0 : root->argList); 05800 #endif 05801 // first note that we pass: 05802 // (root->tArgLists ? root->tArgLists->last() : 0) 05803 // for the template arguments fo the new "member." 05804 // this accurately reflects the template arguments of 05805 // the related function, which don't have to do with 05806 // those of the related class. 05807 MemberDef *md=new MemberDef( 05808 root->fileName,root->startLine, 05809 funcType,funcName,funcArgs,exceptions, 05810 root->protection,root->virt,root->stat,TRUE, 05811 mtype, 05812 (root->tArgLists ? root->tArgLists->last() : 0), 05813 funcArgs.isEmpty() ? 0 : root->argList); 05814 // 05815 // we still have the problem that 05816 // MemberDef::writeDocumentation() in memberdef.cpp 05817 // writes the template argument list for the class, 05818 // as if this member is a member of the class. 05819 // fortunately, MemberDef::writeDocumentation() has 05820 // a special mechanism that allows us to totally 05821 // override the set of template argument lists that 05822 // are printed. We use that and set it to the 05823 // template argument lists of the related function. 05824 // 05825 md->setDefinitionTemplateParameterLists(root->tArgLists); 05826 05827 md->setTagInfo(rootNav->tagInfo()); 05828 05829 05830 05831 //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n", 05832 // funcName.data(),funcDecl.data(),root->bodyLine); 05833 05834 // try to find the matching line number of the body from the 05835 // global function list 05836 bool found=FALSE; 05837 if (root->bodyLine==-1) 05838 { 05839 MemberName *rmn=Doxygen::functionNameSDict->find(funcName); 05840 if (rmn) 05841 { 05842 MemberDef *rmd=rmn->first(); 05843 while (rmd && !found) // see if we got another member with matching arguments 05844 { 05845 LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); 05846 // check for matching argument lists 05847 if ( 05848 matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), 05849 cd,fd,root->argList, 05850 TRUE) 05851 ) 05852 { 05853 found=TRUE; 05854 } 05855 if (!found) rmd=rmn->next(); 05856 } 05857 if (rmd) // member found -> copy line number info 05858 { 05859 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine()); 05860 md->setBodyDef(rmd->getBodyDef()); 05861 //md->setBodyMember(rmd); 05862 } 05863 } 05864 } 05865 if (!found) // line number could not be found or is available in this 05866 // entry 05867 { 05868 md->setBodySegment(root->bodyLine,root->endBodyLine); 05869 md->setBodyDef(fd); 05870 } 05871 05872 //if (root->mGrpId!=-1) 05873 //{ 05874 // md->setMemberGroup(memberGroupDict[root->mGrpId]); 05875 //} 05876 md->setMemberClass(cd); 05877 md->setMemberSpecifiers(root->spec); 05878 md->setDefinition(funcDecl); 05879 md->enableCallGraph(root->callGraph); 05880 md->enableCallerGraph(root->callerGraph); 05881 md->setDocumentation(root->doc,root->docFile,root->docLine); 05882 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 05883 md->setDocsForDefinition(!root->proto); 05884 md->setPrototype(root->proto); 05885 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 05886 md->addSectionsToDefinition(root->anchors); 05887 md->setMemberGroupId(root->mGrpId); 05888 //md->setMemberDefTemplateArguments(root->mtArgList); 05889 mn->append(md); 05890 cd->insertMember(md); 05891 cd->insertUsedFile(root->fileName); 05892 md->setRefItems(root->sli); 05893 if (root->relatesDup) md->setRelatedAlso(cd); 05894 addMemberToGroups(root,md); 05895 //printf("Adding member=%s\n",md->name().data()); 05896 if (newMemberName) 05897 { 05898 //Doxygen::memberNameList.append(mn); 05899 //Doxygen::memberNameDict.insert(funcName,mn); 05900 Doxygen::memberNameSDict->append(funcName,mn); 05901 } 05902 } 05903 if (root->relatesDup) 05904 { 05905 if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl)) 05906 { 05907 QCString fullFuncDecl=funcDecl.copy(); 05908 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); 05909 warn(root->fileName,root->startLine, 05910 "Warning: Cannot determine file/namespace for relatedalso function\n%s", 05911 fullFuncDecl.data() 05912 ); 05913 } 05914 } 05915 } 05916 else 05917 { 05918 warn_undoc(root->fileName,root->startLine, 05919 "Warning: class `%s' for related function `%s' is not " 05920 "documented.", 05921 className.data(),funcName.data() 05922 ); 05923 } 05924 } 05925 else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC) 05926 { 05927 localObjCMethod: 05928 ClassDef *cd; 05929 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); 05930 if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName))) 05931 { 05932 //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data()); 05933 MemberDef *md=new MemberDef( 05934 root->fileName,root->startLine, 05935 funcType,funcName,funcArgs,exceptions, 05936 root->protection,root->virt,root->stat,FALSE, 05937 MemberDef::Function,0,root->argList); 05938 md->setTagInfo(rootNav->tagInfo()); 05939 md->makeImplementationDetail(); 05940 md->setMemberClass(cd); 05941 md->setDefinition(funcDecl); 05942 md->enableCallGraph(root->callGraph); 05943 md->enableCallerGraph(root->callerGraph); 05944 md->setDocumentation(root->doc,root->docFile,root->docLine); 05945 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 05946 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 05947 md->setDocsForDefinition(!root->proto); 05948 md->setPrototype(root->proto); 05949 md->addSectionsToDefinition(root->anchors); 05950 md->setBodySegment(root->bodyLine,root->endBodyLine); 05951 FileDef *fd=rootNav->fileDef(); 05952 md->setBodyDef(fd); 05953 md->setMemberSpecifiers(root->spec); 05954 md->setMemberGroupId(root->mGrpId); 05955 cd->insertMember(md); 05956 cd->insertUsedFile(root->fileName); 05957 md->setRefItems(root->sli); 05958 if ((mn=Doxygen::memberNameSDict->find(root->name))) 05959 { 05960 mn->append(md); 05961 } 05962 else 05963 { 05964 mn = new MemberName(root->name); 05965 mn->append(md); 05966 Doxygen::memberNameSDict->append(root->name,mn); 05967 } 05968 } 05969 else 05970 { 05971 // local objective C method found for class without interface 05972 } 05973 } 05974 else // unrelated not overloaded member found 05975 { 05976 bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl); 05977 if (className.isEmpty() && !globMem) 05978 { 05979 warn(root->fileName,root->startLine, 05980 "Warning: class for member `%s' cannot " 05981 "be found.", funcName.data() 05982 ); 05983 } 05984 else if (!className.isEmpty() && !globMem) 05985 { 05986 warn(root->fileName,root->startLine, 05987 "Warning: member `%s' of class `%s' cannot be found", 05988 funcName.data(),className.data()); 05989 } 05990 } 05991 } 05992 else 05993 { 05994 // this should not be called 05995 warn(root->fileName,root->startLine, 05996 "Warning: member with no name found."); 05997 } 05998 return; 05999 } 06000 06001 //---------------------------------------------------------------------- 06002 // find the members corresponding to the different documentation blocks 06003 // that are extracted from the sources. 06004 06005 static void filterMemberDocumentation(EntryNav *rootNav) 06006 { 06007 Entry *root = rootNav->entry(); 06008 int i=-1,l; 06009 Debug::print(Debug::FindMembers,0, 06010 "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n", 06011 root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId 06012 ); 06013 //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data()); 06014 bool isFunc=TRUE; 06015 06016 if (root->relatesDup && !root->relates.isEmpty()) 06017 { 06018 QCString tmp = root->relates; 06019 root->relates.resize(0); 06020 filterMemberDocumentation(rootNav); 06021 root->relates = tmp; 06022 } 06023 06024 if ( // detect func variable/typedef to func ptr 06025 (i=findFunctionPtr(root->type,&l))!=-1 06026 ) 06027 { 06028 //printf("Fixing function pointer!\n"); 06029 // fix type and argument 06030 root->args.prepend(root->type.right(root->type.length()-i-l)); 06031 root->type=root->type.left(i+l); 06032 //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data()); 06033 isFunc=FALSE; 06034 } 06035 else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) 06036 // detect function types marked as functions 06037 { 06038 isFunc=FALSE; 06039 } 06040 06041 //printf("Member %s isFunc=%d\n",root->name.data(),isFunc); 06042 if (root->section==Entry::MEMBERDOC_SEC) 06043 { 06044 //printf("Documentation for inline member `%s' found args=`%s'\n", 06045 // root->name.data(),root->args.data()); 06046 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data()); 06047 if (root->type.isEmpty()) 06048 { 06049 findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc); 06050 } 06051 else 06052 { 06053 findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc); 06054 } 06055 } 06056 else if (root->section==Entry::OVERLOADDOC_SEC) 06057 { 06058 //printf("Overloaded member %s found\n",root->name.data()); 06059 findMember(rootNav,root->name,TRUE,isFunc); 06060 } 06061 else if 06062 ((root->section==Entry::FUNCTION_SEC // function 06063 || 06064 (root->section==Entry::VARIABLE_SEC && // variable 06065 !root->type.isEmpty() && // with a type 06066 compoundKeywordDict.find(root->type)==0 // that is not a keyword 06067 // (to skip forward declaration of class etc.) 06068 ) 06069 ) 06070 ) 06071 { 06072 //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n", 06073 // root->name.data(),root->args.data(),root->exception.data()); 06074 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data()); 06075 //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data()); 06076 if (root->type=="friend class" || root->type=="friend struct" || 06077 root->type=="friend union") 06078 { 06079 findMember(rootNav, 06080 root->type+" "+ 06081 root->name, 06082 FALSE,FALSE); 06083 06084 } 06085 else if (!root->type.isEmpty()) 06086 { 06087 findMember(rootNav, 06088 root->type+" "+ 06089 root->inside+ 06090 root->name+ 06091 root->args+ 06092 root->exception, 06093 FALSE,isFunc); 06094 } 06095 else 06096 { 06097 findMember(rootNav, 06098 root->inside+ 06099 root->name+ 06100 root->args+ 06101 root->exception, 06102 FALSE,isFunc); 06103 } 06104 } 06105 else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty()) 06106 { 06107 findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty()); 06108 } 06109 else if (root->section==Entry::VARIABLEDOC_SEC) 06110 { 06111 //printf("Documentation for variable %s found\n",root->name.data()); 06112 //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data()); 06113 findMember(rootNav,root->name,FALSE,FALSE); 06114 } 06115 else 06116 { 06117 // skip section 06118 //printf("skip section\n"); 06119 } 06120 } 06121 06122 static void findMemberDocumentation(EntryNav *rootNav) 06123 { 06124 if (rootNav->section()==Entry::MEMBERDOC_SEC || 06125 rootNav->section()==Entry::OVERLOADDOC_SEC || 06126 rootNav->section()==Entry::FUNCTION_SEC || 06127 rootNav->section()==Entry::VARIABLE_SEC || 06128 rootNav->section()==Entry::VARIABLEDOC_SEC || 06129 rootNav->section()==Entry::DEFINE_SEC 06130 ) 06131 { 06132 rootNav->loadEntry(g_storage); 06133 06134 filterMemberDocumentation(rootNav); 06135 06136 rootNav->releaseEntry(); 06137 } 06138 if (rootNav->children()) 06139 { 06140 EntryNavListIterator eli(*rootNav->children()); 06141 EntryNav *e; 06142 for (;(e=eli.current());++eli) 06143 { 06144 if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e); 06145 } 06146 } 06147 } 06148 06149 //---------------------------------------------------------------------- 06150 06151 static void findObjCMethodDefinitions(EntryNav *rootNav) 06152 { 06153 if (rootNav->children()) 06154 { 06155 EntryNavListIterator eli(*rootNav->children()); 06156 EntryNav *objCImplNav; 06157 for (;(objCImplNav=eli.current());++eli) 06158 { 06159 if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children()) 06160 { 06161 EntryNavListIterator seli(*objCImplNav->children()); 06162 EntryNav *objCMethodNav; 06163 for (;(objCMethodNav=seli.current());++seli) 06164 { 06165 if (objCMethodNav->section()==Entry::FUNCTION_SEC) 06166 { 06167 objCMethodNav->loadEntry(g_storage); 06168 Entry *objCMethod = objCMethodNav->entry(); 06169 06170 //Printf(" Found ObjC method definition %s\n",objCMethod->name.data()); 06171 findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+ 06172 objCMethod->name+" "+objCMethod->args, FALSE,TRUE); 06173 objCMethod->section=Entry::EMPTY_SEC; 06174 06175 objCMethodNav->releaseEntry(); 06176 } 06177 } 06178 } 06179 } 06180 } 06181 } 06182 06183 //---------------------------------------------------------------------- 06184 // find and add the enumeration to their classes, namespaces or files 06185 06186 static void findEnums(EntryNav *rootNav) 06187 { 06188 if (rootNav->section()==Entry::ENUM_SEC) 06189 // non anonymous enumeration 06190 { 06191 rootNav->loadEntry(g_storage); 06192 Entry *root = rootNav->entry(); 06193 06194 MemberDef *md=0; 06195 ClassDef *cd=0; 06196 FileDef *fd=0; 06197 NamespaceDef *nd=0; 06198 MemberNameSDict *mnsd=0; 06199 bool isGlobal; 06200 bool isRelated=FALSE; 06201 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data()); 06202 int i; 06203 06204 QCString name; 06205 QCString scope; 06206 06207 if ((i=root->name.findRev("::"))!=-1) // scope is specified 06208 { 06209 scope=root->name.left(i); // extract scope 06210 name=root->name.right(root->name.length()-i-2); // extract name 06211 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); 06212 } 06213 else // no scope, check the scope in which the docs where found 06214 { 06215 if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) 06216 && !rootNav->parent()->name().isEmpty() 06217 ) // found enum docs inside a compound 06218 { 06219 scope=rootNav->parent()->name(); 06220 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); 06221 } 06222 name=root->name; 06223 } 06224 06225 if (!root->relates.isEmpty()) 06226 { // related member, prefix user specified scope 06227 isRelated=TRUE; 06228 if (getClass(root->relates)==0 && !scope.isEmpty()) 06229 scope=mergeScopes(scope,root->relates); 06230 else 06231 scope=root->relates.copy(); 06232 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); 06233 } 06234 06235 if (cd && !name.isEmpty()) // found a enum inside a compound 06236 { 06237 //printf("Enum `%s'::`%s'\n",cd->name(),name.data()); 06238 fd=0; 06239 mnsd=Doxygen::memberNameSDict; 06240 isGlobal=FALSE; 06241 } 06242 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace 06243 { 06244 mnsd=Doxygen::functionNameSDict; 06245 isGlobal=TRUE; 06246 } 06247 else // found a global enum 06248 { 06249 fd=rootNav->fileDef(); 06250 mnsd=Doxygen::functionNameSDict; 06251 isGlobal=TRUE; 06252 } 06253 06254 if (!name.isEmpty()) 06255 { 06256 // new enum type 06257 md = new MemberDef( 06258 root->fileName,root->startLine, 06259 0,name,0,0, 06260 root->protection,Normal,FALSE,isRelated,MemberDef::Enumeration, 06261 0,0); 06262 md->setTagInfo(rootNav->tagInfo()); 06263 if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd); 06264 md->setBodySegment(root->bodyLine,root->endBodyLine); 06265 md->setBodyDef(rootNav->fileDef()); 06266 //printf("Enum %s definition at line %d of %s: protection=%d\n", 06267 // root->name.data(),root->bodyLine,root->fileName.data(),root->protection); 06268 md->addSectionsToDefinition(root->anchors); 06269 md->setMemberGroupId(root->mGrpId); 06270 md->enableCallGraph(root->callGraph); 06271 md->enableCallerGraph(root->callerGraph); 06272 md->setRefItems(root->sli); 06273 //printf("found enum %s nd=%p\n",name.data(),nd); 06274 bool defSet=FALSE; 06275 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') 06276 { 06277 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES")) 06278 { 06279 md->setDefinition(name); 06280 } 06281 else 06282 { 06283 md->setDefinition(nd->name()+"::"+name); 06284 } 06285 //printf("definition=%s\n",md->definition()); 06286 defSet=TRUE; 06287 md->setNamespace(nd); 06288 nd->insertMember(md); 06289 } 06290 06291 // even if we have already added the enum to a namespace, we still 06292 // also want to add it to other appropriate places such as file 06293 // or class. 06294 if (isGlobal) 06295 { 06296 if (!defSet) md->setDefinition(name); 06297 if (fd==0 && rootNav->parent()) 06298 { 06299 fd=rootNav->parent()->fileDef(); 06300 } 06301 if (fd) 06302 { 06303 md->setFileDef(fd); 06304 fd->insertMember(md); 06305 } 06306 } 06307 else if (cd) 06308 { 06309 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES")) 06310 { 06311 md->setDefinition(name); 06312 } 06313 else 06314 { 06315 md->setDefinition(cd->name()+"::"+name); 06316 } 06317 cd->insertMember(md); 06318 cd->insertUsedFile(root->fileName); 06319 } 06320 md->setDocumentation(root->doc,root->docFile,root->docLine); 06321 md->setDocsForDefinition(!root->proto); 06322 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 06323 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 06324 06325 //printf("Adding member=%s\n",md->name().data()); 06326 MemberName *mn; 06327 if ((mn=(*mnsd)[name])) 06328 { 06329 // this is used if the same enum is in multiple namespaces/classes 06330 mn->append(md); 06331 } 06332 else // new enum name 06333 { 06334 mn = new MemberName(name); 06335 mn->append(md); 06336 mnsd->append(name,mn); 06337 //printf("add %s to new memberName. Now %d members\n", 06338 // name.data(),mn->count()); 06339 } 06340 addMemberToGroups(root,md); 06341 06342 #if 0 06343 if (rootNav->children()) 06344 { 06345 EntryNavListIterator eli(*rootNav->children()); 06346 EntryNav *e; 06347 for (;(e=eli.current());++eli) 06348 { 06349 //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated); 06350 MemberName *fmn=0; 06351 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd; 06352 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 06353 // get list of members with the same name as the field 06354 { 06355 MemberNameIterator fmni(*fmn); 06356 MemberDef *fmd; 06357 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 06358 { 06359 if (fmd->isEnumValue()) 06360 { 06361 //printf("found enum value with same name\n"); 06362 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') 06363 { 06364 NamespaceDef *fnd=fmd->getNamespaceDef(); 06365 if (fnd==nd) // enum value is inside a namespace 06366 { 06367 md->insertEnumField(fmd); 06368 fmd->setEnumScope(md); 06369 } 06370 } 06371 else if (isGlobal) 06372 { 06373 FileDef *ffd=fmd->getFileDef(); 06374 if (ffd==fd) // enum value has file scope 06375 { 06376 md->insertEnumField(fmd); 06377 fmd->setEnumScope(md); 06378 } 06379 } 06380 else if (isRelated && cd) // reparent enum value to 06381 // match the enum's scope 06382 { 06383 md->insertEnumField(fmd); // add field def to list 06384 fmd->setEnumScope(md); // cross ref with enum name 06385 fmd->setEnumClassScope(cd); // cross ref with enum name 06386 fmd->setOuterScope(cd); 06387 fmd->makeRelated(); 06388 cd->insertMember(fmd); 06389 } 06390 else 06391 { 06392 ClassDef *fcd=fmd->getClassDef(); 06393 if (fcd==cd) // enum value is inside a class 06394 { 06395 //printf("Inserting enum field %s in enum scope %s\n", 06396 // fmd->name().data(),md->name().data()); 06397 md->insertEnumField(fmd); // add field def to list 06398 fmd->setEnumScope(md); // cross ref with enum name 06399 } 06400 } 06401 } 06402 } 06403 } 06404 } 06405 } 06406 #endif 06407 } 06408 06409 rootNav->releaseEntry(); 06410 } 06411 else 06412 { 06413 RECURSE_ENTRYTREE(findEnums,rootNav); 06414 } 06415 } 06416 06417 //---------------------------------------------------------------------- 06418 06419 static void addEnumValuesToEnums(EntryNav *rootNav) 06420 { 06421 if (rootNav->section()==Entry::ENUM_SEC) 06422 // non anonymous enumeration 06423 { 06424 rootNav->loadEntry(g_storage); 06425 Entry *root = rootNav->entry(); 06426 06427 ClassDef *cd=0; 06428 FileDef *fd=0; 06429 NamespaceDef *nd=0; 06430 MemberNameSDict *mnsd=0; 06431 bool isGlobal; 06432 bool isRelated=FALSE; 06433 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data()); 06434 int i; 06435 06436 QCString name; 06437 QCString scope; 06438 06439 if ((i=root->name.findRev("::"))!=-1) // scope is specified 06440 { 06441 scope=root->name.left(i); // extract scope 06442 name=root->name.right(root->name.length()-i-2); // extract name 06443 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); 06444 } 06445 else // no scope, check the scope in which the docs where found 06446 { 06447 if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) 06448 && !rootNav->parent()->name().isEmpty() 06449 ) // found enum docs inside a compound 06450 { 06451 scope=rootNav->parent()->name(); 06452 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); 06453 } 06454 name=root->name; 06455 } 06456 06457 if (!root->relates.isEmpty()) 06458 { // related member, prefix user specified scope 06459 isRelated=TRUE; 06460 if (getClass(root->relates)==0 && !scope.isEmpty()) 06461 scope=mergeScopes(scope,root->relates); 06462 else 06463 scope=root->relates.copy(); 06464 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); 06465 } 06466 06467 if (cd && !name.isEmpty()) // found a enum inside a compound 06468 { 06469 //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data()); 06470 fd=0; 06471 mnsd=Doxygen::memberNameSDict; 06472 isGlobal=FALSE; 06473 } 06474 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace 06475 { 06476 //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data()); 06477 mnsd=Doxygen::functionNameSDict; 06478 isGlobal=TRUE; 06479 } 06480 else // found a global enum 06481 { 06482 fd=rootNav->fileDef(); 06483 //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data()); 06484 mnsd=Doxygen::functionNameSDict; 06485 isGlobal=TRUE; 06486 } 06487 06488 if (!name.isEmpty()) 06489 { 06490 MemberName *mn = mnsd->find(name); // for all members with this name 06491 if (mn) 06492 { 06493 MemberNameIterator mni(*mn); 06494 MemberDef *md; 06495 for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list 06496 { 06497 if (md->isEnumerate() && rootNav->children()) 06498 { 06499 EntryNavListIterator eli(*rootNav->children()); // for each enum value 06500 EntryNav *e; 06501 for (;(e=eli.current());++eli) 06502 { 06503 SrcLangExt sle; 06504 if (rootNav->fileDef() && 06505 ( (sle=getLanguageFromFileName(rootNav->fileDef()->name()))==SrcLangExt_CSharp 06506 || sle==SrcLangExt_Java 06507 ) 06508 ) 06509 { 06510 // For C# enum value are only inside the enum scope, so we 06511 // must create them here 06512 e->loadEntry(g_storage); 06513 MemberDef *fmd = addVariableToFile(e,MemberDef::EnumValue, 06514 md->getOuterScope() ? md->getOuterScope()->name() : QCString(), 06515 e->name(),TRUE,0); 06516 md->insertEnumField(fmd); 06517 fmd->setEnumScope(md); 06518 e->releaseEntry(); 06519 } 06520 else 06521 { 06522 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated); 06523 MemberName *fmn=0; 06524 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd; 06525 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) 06526 // get list of members with the same name as the field 06527 { 06528 MemberNameIterator fmni(*fmn); 06529 MemberDef *fmd; 06530 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) 06531 { 06532 if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope 06533 { 06534 //printf("found enum value with same name %s in scope %s\n", 06535 // fmd->name().data(),fmd->getOuterScope()->name().data()); 06536 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') 06537 { 06538 NamespaceDef *fnd=fmd->getNamespaceDef(); 06539 if (fnd==nd) // enum value is inside a namespace 06540 { 06541 md->insertEnumField(fmd); 06542 fmd->setEnumScope(md); 06543 } 06544 } 06545 else if (isGlobal) 06546 { 06547 FileDef *ffd=fmd->getFileDef(); 06548 if (ffd==fd) // enum value has file scope 06549 { 06550 md->insertEnumField(fmd); 06551 fmd->setEnumScope(md); 06552 } 06553 } 06554 else if (isRelated && cd) // reparent enum value to 06555 // match the enum's scope 06556 { 06557 md->insertEnumField(fmd); // add field def to list 06558 fmd->setEnumScope(md); // cross ref with enum name 06559 fmd->setEnumClassScope(cd); // cross ref with enum name 06560 fmd->setOuterScope(cd); 06561 fmd->makeRelated(); 06562 cd->insertMember(fmd); 06563 } 06564 else 06565 { 06566 ClassDef *fcd=fmd->getClassDef(); 06567 if (fcd==cd) // enum value is inside a class 06568 { 06569 //printf("Inserting enum field %s in enum scope %s\n", 06570 // fmd->name().data(),md->name().data()); 06571 md->insertEnumField(fmd); // add field def to list 06572 fmd->setEnumScope(md); // cross ref with enum name 06573 } 06574 } 06575 } 06576 } 06577 } 06578 } 06579 } 06580 } 06581 } 06582 } 06583 } 06584 06585 rootNav->releaseEntry(); 06586 } 06587 else 06588 { 06589 RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav); 06590 } 06591 } 06592 06593 06594 //---------------------------------------------------------------------- 06595 // find the documentation blocks for the enumerations 06596 06597 static void findEnumDocumentation(EntryNav *rootNav) 06598 { 06599 if (rootNav->section()==Entry::ENUMDOC_SEC 06600 && !rootNav->name().isEmpty() 06601 && rootNav->name().at(0)!='@' // skip anonymous enums 06602 ) 06603 { 06604 rootNav->loadEntry(g_storage); 06605 Entry *root = rootNav->entry(); 06606 06607 //printf("Found docs for enum with name `%s' in context %s\n", 06608 // root->name.data(),root->parent->name.data()); 06609 int i; 06610 QCString name; 06611 QCString scope; 06612 if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name 06613 { 06614 name=root->name.right(root->name.length()-i-2); // extract name 06615 scope=root->name.left(i); // extract scope 06616 //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data()); 06617 } 06618 else // just the name 06619 { 06620 name=root->name; 06621 } 06622 if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) 06623 && !rootNav->parent()->name().isEmpty() 06624 ) // found enum docs inside a compound 06625 { 06626 if (!scope.isEmpty()) scope.prepend("::"); 06627 scope.prepend(rootNav->parent()->name()); 06628 } 06629 ClassDef *cd=getClass(scope); 06630 06631 if (!name.isEmpty()) 06632 { 06633 bool found=FALSE; 06634 if (cd) 06635 { 06636 //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data()); 06637 QCString className=cd->name().copy(); 06638 MemberName *mn=Doxygen::memberNameSDict->find(name); 06639 if (mn) 06640 { 06641 MemberNameIterator mni(*mn); 06642 MemberDef *md; 06643 for (mni.toFirst();(md=mni.current()) && !found;++mni) 06644 { 06645 ClassDef *cd=md->getClassDef(); 06646 if (cd && cd->name()==className && md->isEnumerate()) 06647 { 06648 // documentation outside a compound overrides the documentation inside it 06649 #if 0 06650 if (!md->documentation() || rootNav->parent()->name().isEmpty()) 06651 #endif 06652 { 06653 md->setDocumentation(root->doc,root->docFile,root->docLine); 06654 md->setDocsForDefinition(!root->proto); 06655 } 06656 06657 // brief descriptions inside a compound override the documentation 06658 // outside it 06659 #if 0 06660 if (!md->briefDescription() || !rootNav->parent()->name().isEmpty()) 06661 #endif 06662 { 06663 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 06664 } 06665 06666 if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty()) 06667 { 06668 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 06669 } 06670 06671 if (root->mGrpId!=-1 && md->getMemberGroupId()==-1) 06672 { 06673 md->setMemberGroupId(root->mGrpId); 06674 } 06675 06676 md->addSectionsToDefinition(root->anchors); 06677 06678 GroupDef *gd=md->getGroupDef(); 06679 if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is 06680 { 06681 addMemberToGroups(root,md); 06682 } 06683 06684 found=TRUE; 06685 } 06686 } 06687 } 06688 else 06689 { 06690 //printf("MemberName %s not found!\n",name.data()); 06691 } 06692 } 06693 else // enum outside class 06694 { 06695 //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId); 06696 MemberName *mn=Doxygen::functionNameSDict->find(name); 06697 if (mn) 06698 { 06699 MemberNameIterator mni(*mn); 06700 MemberDef *md; 06701 for (mni.toFirst();(md=mni.current()) && !found;++mni) 06702 { 06703 if (md->isEnumerate()) 06704 { 06705 md->setDocumentation(root->doc,root->docFile,root->docLine); 06706 md->setDocsForDefinition(!root->proto); 06707 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 06708 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 06709 md->addSectionsToDefinition(root->anchors); 06710 md->setMemberGroupId(root->mGrpId); 06711 06712 GroupDef *gd=md->getGroupDef(); 06713 if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is 06714 { 06715 addMemberToGroups(root,md); 06716 } 06717 06718 found=TRUE; 06719 } 06720 } 06721 } 06722 } 06723 if (!found) 06724 { 06725 warn(root->fileName,root->startLine, 06726 "Warning: Documentation for undefined enum `%s' found.", 06727 name.data() 06728 ); 06729 } 06730 } 06731 06732 rootNav->releaseEntry(); 06733 } 06734 RECURSE_ENTRYTREE(findEnumDocumentation,rootNav); 06735 } 06736 06737 // seach for each enum (member or function) in mnl if it has documented 06738 // enum values. 06739 static void findDEV(const MemberNameSDict &mnsd) 06740 { 06741 MemberName *mn; 06742 MemberNameSDict::Iterator mnli(mnsd); 06743 // for each member name 06744 for (mnli.toFirst();(mn=mnli.current());++mnli) 06745 { 06746 MemberDef *md; 06747 MemberNameIterator mni(*mn); 06748 // for each member definition 06749 for (mni.toFirst();(md=mni.current());++mni) 06750 { 06751 if (md->isEnumerate()) // member is an enum 06752 { 06753 LockingPtr<MemberList> fmdl = md->enumFieldList(); 06754 int documentedEnumValues=0; 06755 if (fmdl!=0) // enum has values 06756 { 06757 MemberListIterator fmni(*fmdl); 06758 MemberDef *fmd; 06759 // for each enum value 06760 for (fmni.toFirst();(fmd=fmni.current());++fmni) 06761 { 06762 if (fmd->isLinkableInProject()) documentedEnumValues++; 06763 } 06764 } 06765 // at least one enum value is documented 06766 if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE); 06767 } 06768 } 06769 } 06770 } 06771 06772 // seach for each enum (member or function) if it has documented enum 06773 // values. 06774 static void findDocumentedEnumValues() 06775 { 06776 findDEV(*Doxygen::memberNameSDict); 06777 findDEV(*Doxygen::functionNameSDict); 06778 } 06779 06780 //---------------------------------------------------------------------- 06781 06782 static void addMembersToIndex() 06783 { 06784 MemberName *mn; 06785 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); 06786 // for each member name 06787 for (mnli.toFirst();(mn=mnli.current());++mnli) 06788 { 06789 MemberDef *md; 06790 MemberNameIterator mni(*mn); 06791 // for each member definition 06792 for (mni.toFirst();(md=mni.current());++mni) 06793 { 06794 addClassMemberNameToIndex(md); 06795 } 06796 } 06797 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); 06798 // for each member name 06799 for (fnli.toFirst();(mn=fnli.current());++fnli) 06800 { 06801 MemberDef *md; 06802 MemberNameIterator mni(*mn); 06803 // for each member definition 06804 for (mni.toFirst();(md=mni.current());++mni) 06805 { 06806 if (md->getNamespaceDef()) 06807 { 06808 addNamespaceMemberNameToIndex(md); 06809 } 06810 else 06811 { 06812 addFileMemberNameToIndex(md); 06813 } 06814 } 06815 } 06816 } 06817 06818 //---------------------------------------------------------------------- 06819 // computes the relation between all members. For each member `m' 06820 // the members that override the implementation of `m' are searched and 06821 // the member that `m' overrides is searched. 06822 06823 static void computeMemberRelations() 06824 { 06825 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); 06826 MemberName *mn; 06827 for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name 06828 { 06829 MemberNameIterator mdi(*mn); 06830 MemberDef *md; 06831 for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific arg list 06832 { 06833 MemberNameIterator bmdi(*mn); 06834 MemberDef *bmd; 06835 for ( ; (bmd=bmdi.current()) ; ++bmdi ) // for each other member with that signature 06836 { 06837 ClassDef *bmcd = bmd->getClassDef(); 06838 ClassDef *mcd = md->getClassDef(); 06839 //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n", 06840 // mcd->name().data(),md->name().data(),md, 06841 // bmcd->name().data(),bmd->name().data(),bmd 06842 // ); 06843 if (md!=bmd && bmcd && mcd && bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE)) 06844 { 06845 //printf(" Base argList=`%s'\n Super argList=`%s'\n", 06846 // argListToString(bmd->argumentList()).data(), 06847 // argListToString(md->argumentList()).data() 06848 // ); 06849 LockingPtr<ArgumentList> bmdAl = bmd->argumentList(); 06850 LockingPtr<ArgumentList> mdAl = md->argumentList(); 06851 if ( 06852 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(), 06853 md->getOuterScope(), md->getFileDef(), mdAl.pointer(), 06854 TRUE 06855 ) 06856 ) 06857 { 06858 //printf(" match found!\n"); 06859 if (mcd && bmcd && 06860 mcd->isLinkable() && bmcd->isLinkable() 06861 ) 06862 { 06863 MemberDef *rmd; 06864 if ((rmd=md->reimplements())==0 || 06865 minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef()) 06866 ) 06867 { 06868 //printf("setting (new) reimplements member\n"); 06869 md->setReimplements(bmd); 06870 } 06871 //printf("%s: add reimplements member %s\n",mcd->name().data(),bmcd->name().data()); 06872 //md->setImplements(bmd); 06873 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data()); 06874 bmd->insertReimplementedBy(md); 06875 } 06876 } 06877 } 06878 } 06879 } 06880 } 06881 } 06882 06883 06884 //---------------------------------------------------------------------------- 06885 //static void computeClassImplUsageRelations() 06886 //{ 06887 // ClassDef *cd; 06888 // ClassSDict::Iterator cli(*Doxygen::classSDict); 06889 // for (;(cd=cli.current());++cli) 06890 // { 06891 // cd->determineImplUsageRelation(); 06892 // } 06893 //} 06894 06895 //---------------------------------------------------------------------------- 06896 06897 static void createTemplateInstanceMembers() 06898 { 06899 ClassSDict::Iterator cli(*Doxygen::classSDict); 06900 ClassDef *cd; 06901 // for each class 06902 for (cli.toFirst();(cd=cli.current());++cli) 06903 { 06904 // that is a template 06905 QDict<ClassDef> *templInstances = cd->getTemplateInstances(); 06906 if (templInstances) 06907 { 06908 QDictIterator<ClassDef> qdi(*templInstances); 06909 ClassDef *tcd=0; 06910 // for each instance of the template 06911 for (qdi.toFirst();(tcd=qdi.current());++qdi) 06912 { 06913 tcd->addMembersToTemplateInstance(cd,qdi.currentKey()); 06914 } 06915 } 06916 } 06917 } 06918 06919 //---------------------------------------------------------------------------- 06920 06921 // builds the list of all members for each class 06922 06923 static void buildCompleteMemberLists() 06924 { 06925 ClassDef *cd; 06926 // merge members of categories into the class they extend 06927 ClassSDict::Iterator cli(*Doxygen::classSDict); 06928 for (cli.toFirst();(cd=cli.current());++cli) 06929 { 06930 int i=cd->name().find('('); 06931 if (i!=-1) // it is an Objective-C category 06932 { 06933 QCString baseName=cd->name().left(i); 06934 ClassDef *baseClass=Doxygen::classSDict->find(baseName); 06935 if (baseClass) 06936 { 06937 //printf("*** merging members of category %s into %s\n", 06938 // cd->name().data(),baseClass->name().data()); 06939 baseClass->mergeCategory(cd); 06940 } 06941 } 06942 } 06943 // merge the member list of base classes into the inherited classes. 06944 for (cli.toFirst();(cd=cli.current());++cli) 06945 { 06946 if (// !cd->isReference() && // not an external class 06947 cd->subClasses()==0 && // is a root of the hierarchy 06948 cd->baseClasses()) // and has at least one base class 06949 { 06950 //printf("*** merging members for %s\n",cd->name().data()); 06951 cd->mergeMembers(); 06952 } 06953 } 06954 // now sort the member list of all classes. 06955 for (cli.toFirst();(cd=cli.current());++cli) 06956 { 06957 if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort(); 06958 } 06959 } 06960 06961 //---------------------------------------------------------------------------- 06962 06963 static void generateFileSources() 06964 { 06965 if (documentedHtmlFiles==0) return; 06966 if (Doxygen::inputNameList->count()>0) 06967 { 06968 FileNameListIterator fnli(*Doxygen::inputNameList); 06969 FileName *fn; 06970 for (;(fn=fnli.current());++fnli) 06971 { 06972 FileNameIterator fni(*fn); 06973 FileDef *fd; 06974 for (;(fd=fni.current());++fni) 06975 { 06976 if (fd->generateSourceFile()) // sources need to be shown in the output 06977 { 06978 msg("Generating code for file %s...\n",fd->docName().data()); 06979 fd->writeSource(*outputList); 06980 } 06981 else if (!fd->isReference() && Doxygen::parseSourcesNeeded) 06982 // we needed to parse the sources even if we do not show them 06983 { 06984 msg("Parsing code for file %s...\n",fd->docName().data()); 06985 fd->parseSource(); 06986 } 06987 } 06988 } 06989 } 06990 } 06991 06992 //---------------------------------------------------------------------------- 06993 06994 static void generateFileDocs() 06995 { 06996 if (documentedHtmlFiles==0) return; 06997 06998 if (Doxygen::inputNameList->count()>0) 06999 { 07000 FileNameListIterator fnli(*Doxygen::inputNameList); 07001 FileName *fn; 07002 for (fnli.toFirst();(fn=fnli.current());++fnli) 07003 { 07004 FileNameIterator fni(*fn); 07005 FileDef *fd; 07006 for (fni.toFirst();(fd=fni.current());++fni) 07007 { 07008 bool doc = fd->isLinkableInProject(); 07009 if (doc) 07010 { 07011 msg("Generating docs for file %s...\n",fd->docName().data()); 07012 fd->writeDocumentation(*outputList); 07013 } 07014 } 07015 } 07016 } 07017 } 07018 07019 //---------------------------------------------------------------------------- 07020 07021 static void addSourceReferences() 07022 { 07023 // add source references for class definitions 07024 ClassSDict::Iterator cli(*Doxygen::classSDict); 07025 ClassDef *cd=0; 07026 for (cli.toFirst();(cd=cli.current());++cli) 07027 { 07028 FileDef *fd=cd->getBodyDef(); 07029 if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1) 07030 { 07031 fd->addSourceRef(cd->getStartBodyLine(),cd,0); 07032 } 07033 } 07034 // add source references for namespace definitions 07035 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); 07036 NamespaceDef *nd=0; 07037 for (nli.toFirst();(nd=nli.current());++nli) 07038 { 07039 FileDef *fd=nd->getBodyDef(); 07040 if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1) 07041 { 07042 fd->addSourceRef(nd->getStartBodyLine(),nd,0); 07043 } 07044 } 07045 07046 // add source references for member names 07047 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); 07048 MemberName *mn=0; 07049 for (mnli.toFirst();(mn=mnli.current());++mnli) 07050 { 07051 MemberNameIterator mni(*mn); 07052 MemberDef *md=0; 07053 for (mni.toFirst();(md=mni.current());++mni) 07054 { 07055 //printf("class member %s\n",md->name().data()); 07056 FileDef *fd=md->getBodyDef(); 07057 if (fd && 07058 md->getStartBodyLine()!=-1 && 07059 md->isLinkableInProject() && 07060 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded) 07061 ) 07062 { 07063 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n", 07064 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 07065 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md); 07066 } 07067 } 07068 } 07069 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); 07070 for (fnli.toFirst();(mn=fnli.current());++fnli) 07071 { 07072 MemberNameIterator mni(*mn); 07073 MemberDef *md=0; 07074 for (mni.toFirst();(md=mni.current());++mni) 07075 { 07076 FileDef *fd=md->getBodyDef(); 07077 //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n", 07078 // md->name().data(), 07079 // md->getStartBodyLine(),md->getEndBodyLine(),fd, 07080 // md->isLinkableInProject(), 07081 // Doxygen::parseSourcesNeeded); 07082 if (fd && 07083 md->getStartBodyLine()!=-1 && 07084 md->isLinkableInProject() && 07085 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded) 07086 ) 07087 { 07088 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n", 07089 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); 07090 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md); 07091 } 07092 } 07093 } 07094 } 07095 07096 //---------------------------------------------------------------------------- 07097 // generate the documentation of all classes 07098 07099 static void generateClassList(ClassSDict &classSDict) 07100 { 07101 ClassSDict::Iterator cli(classSDict); 07102 for ( ; cli.current() ; ++cli ) 07103 { 07104 ClassDef *cd=cli.current(); 07105 07106 //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope); 07107 if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file 07108 cd->getOuterScope()==Doxygen::globalScope // only look at global classes 07109 ) && !cd->isHidden() 07110 ) 07111 { 07112 // skip external references, anonymous compounds and 07113 // template instances 07114 if ( cd->isLinkableInProject() && cd->templateMaster()==0) 07115 { 07116 msg("Generating docs for compound %s...\n",cd->name().data()); 07117 07118 cd->writeDocumentation(*outputList); 07119 cd->writeMemberList(*outputList); 07120 } 07121 // even for undocumented classes, the inner classes can be documented. 07122 cd->writeDocumentationForInnerClasses(*outputList); 07123 } 07124 } 07125 } 07126 07127 static void generateClassDocs() 07128 { 07129 // write the installdox script if necessary 07130 if (Config_getBool("GENERATE_HTML") && 07131 (Config_getList("TAGFILES").count()>0 || 07132 Config_getBool("SEARCHENGINE") 07133 ) 07134 ) 07135 { 07136 writeInstallScript(); 07137 } 07138 07139 msg("Generating annotated compound index...\n"); 07140 writeAnnotatedIndex(*outputList); 07141 07142 if (Config_getBool("ALPHABETICAL_INDEX")) 07143 { 07144 msg("Generating alphabetical compound index...\n"); 07145 writeAlphabeticalIndex(*outputList); 07146 } 07147 07148 msg("Generating hierarchical class index...\n"); 07149 writeHierarchicalIndex(*outputList); 07150 07151 msg("Generating member index...\n"); 07152 writeClassMemberIndex(*outputList); 07153 07154 if (Doxygen::exampleSDict->count()>0) 07155 { 07156 msg("Generating example index...\n"); 07157 } 07158 07159 generateClassList(*Doxygen::classSDict); 07160 generateClassList(*Doxygen::hiddenClasses); 07161 } 07162 07163 //---------------------------------------------------------------------------- 07164 07165 static void inheritDocumentation() 07166 { 07167 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); 07168 MemberName *mn; 07169 //int count=0; 07170 for (;(mn=mnli.current());++mnli) 07171 { 07172 MemberNameIterator mni(*mn); 07173 MemberDef *md; 07174 for (;(md=mni.current());++mni) 07175 { 07176 //printf("%04d Member `%s'\n",count++,md->name().data()); 07177 if (md->documentation().isEmpty() && md->briefDescription().isEmpty()) 07178 { // no documentation yet 07179 MemberDef *bmd = md->reimplements(); 07180 while (bmd && bmd->documentation().isEmpty() && 07181 bmd->briefDescription().isEmpty() 07182 ) 07183 { // search up the inheritance tree for a documentation member 07184 //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data()); 07185 bmd = bmd->reimplements(); 07186 } 07187 if (bmd) // copy the documentation from the reimplemented member 07188 { 07189 md->setInheritsDocsFrom(bmd); 07190 md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine()); 07191 md->setDocsForDefinition(bmd->isDocsForDefinition()); 07192 md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine()); 07193 md->copyArgumentNames(bmd); 07194 md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine()); 07195 } 07196 } 07197 } 07198 } 07199 } 07200 07201 //---------------------------------------------------------------------------- 07202 07203 static void combineUsingRelations() 07204 { 07205 // for each file 07206 FileNameListIterator fnli(*Doxygen::inputNameList); 07207 FileName *fn; 07208 for (fnli.toFirst();(fn=fnli.current());++fnli) 07209 { 07210 FileNameIterator fni(*fn); 07211 FileDef *fd; 07212 for (fni.toFirst();(fd=fni.current());++fni) 07213 { 07214 fd->visited=FALSE; 07215 } 07216 } 07217 for (fnli.toFirst();(fn=fnli.current());++fnli) 07218 { 07219 FileNameIterator fni(*fn); 07220 FileDef *fd; 07221 for (fni.toFirst();(fd=fni.current());++fni) 07222 { 07223 fd->combineUsingRelations(); 07224 } 07225 } 07226 07227 // for each namespace 07228 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); 07229 NamespaceDef *nd; 07230 for (nli.toFirst() ; (nd=nli.current()) ; ++nli ) 07231 { 07232 nd->visited=FALSE; 07233 } 07234 for (nli.toFirst() ; (nd=nli.current()) ; ++nli ) 07235 { 07236 nd->combineUsingRelations(); 07237 } 07238 } 07239 07240 //---------------------------------------------------------------------------- 07241 07242 static void addMembersToMemberGroup() 07243 { 07244 // for each class 07245 ClassSDict::Iterator cli(*Doxygen::classSDict); 07246 ClassDef *cd; 07247 for ( ; (cd=cli.current()) ; ++cli ) 07248 { 07249 cd->addMembersToMemberGroup(); 07250 } 07251 // for each file 07252 FileName *fn=Doxygen::inputNameList->first(); 07253 while (fn) 07254 { 07255 FileDef *fd=fn->first(); 07256 while (fd) 07257 { 07258 fd->addMembersToMemberGroup(); 07259 fd=fn->next(); 07260 } 07261 fn=Doxygen::inputNameList->next(); 07262 } 07263 // for each namespace 07264 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); 07265 NamespaceDef *nd; 07266 for ( ; (nd=nli.current()) ; ++nli ) 07267 { 07268 nd->addMembersToMemberGroup(); 07269 } 07270 // for each group 07271 GroupSDict::Iterator gli(*Doxygen::groupSDict); 07272 GroupDef *gd; 07273 for (gli.toFirst();(gd=gli.current());++gli) 07274 { 07275 gd->addMembersToMemberGroup(); 07276 } 07277 } 07278 07279 //---------------------------------------------------------------------------- 07280 07281 static void distributeMemberGroupDocumentation() 07282 { 07283 // for each class 07284 ClassSDict::Iterator cli(*Doxygen::classSDict); 07285 ClassDef *cd; 07286 for ( ; (cd=cli.current()) ; ++cli ) 07287 { 07288 cd->distributeMemberGroupDocumentation(); 07289 } 07290 // for each file 07291 FileName *fn=Doxygen::inputNameList->first(); 07292 while (fn) 07293 { 07294 FileDef *fd=fn->first(); 07295 while (fd) 07296 { 07297 fd->distributeMemberGroupDocumentation(); 07298 fd=fn->next(); 07299 } 07300 fn=Doxygen::inputNameList->next(); 07301 } 07302 // for each namespace 07303 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); 07304 NamespaceDef *nd; 07305 for ( ; (nd=nli.current()) ; ++nli ) 07306 { 07307 nd->distributeMemberGroupDocumentation(); 07308 } 07309 // for each group 07310 GroupSDict::Iterator gli(*Doxygen::groupSDict); 07311 GroupDef *gd; 07312 for (gli.toFirst();(gd=gli.current());++gli) 07313 { 07314 gd->distributeMemberGroupDocumentation(); 07315 } 07316 } 07317 07318 //---------------------------------------------------------------------------- 07319 07320 static void findSectionsInDocumentation() 07321 { 07322 // for each class 07323 ClassSDict::Iterator cli(*Doxygen::classSDict); 07324 ClassDef *cd; 07325 for ( ; (cd=cli.current()) ; ++cli ) 07326 { 07327 cd->findSectionsInDocumentation(); 07328 } 07329 // for each file 07330 FileName *fn=Doxygen::inputNameList->first(); 07331 while (fn) 07332 { 07333 FileDef *fd=fn->first(); 07334 while (fd) 07335 { 07336 fd->findSectionsInDocumentation(); 07337 fd=fn->next(); 07338 } 07339 fn=Doxygen::inputNameList->next(); 07340 } 07341 // for each namespace 07342 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); 07343 NamespaceDef *nd; 07344 for ( ; (nd=nli.current()) ; ++nli ) 07345 { 07346 nd->findSectionsInDocumentation(); 07347 } 07348 // for each group 07349 GroupSDict::Iterator gli(*Doxygen::groupSDict); 07350 GroupDef *gd; 07351 for (gli.toFirst();(gd=gli.current());++gli) 07352 { 07353 gd->findSectionsInDocumentation(); 07354 } 07355 // for each page 07356 PageSDict::Iterator pdi(*Doxygen::pageSDict); 07357 PageDef *pd=0; 07358 for (pdi.toFirst();(pd=pdi.current());++pdi) 07359 { 07360 pd->findSectionsInDocumentation(); 07361 } 07362 if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation(); 07363 } 07364 07365 static void flushCachedTemplateRelations() 07366 { 07367 // remove all references to classes from the cache 07368 // as there can be new template instances in the inheritance path 07369 // to this class. Optimization: only remove those classes that 07370 // have inheritance instances as direct or indirect sub classes. 07371 QCacheIterator<LookupInfo> ci(Doxygen::lookupCache); 07372 LookupInfo *li=0; 07373 for (ci.toFirst();(li=ci.current());++ci) 07374 { 07375 if (li->classDef) 07376 { 07377 Doxygen::lookupCache.remove(ci.currentKey()); 07378 } 07379 } 07380 // remove all cached typedef resolutions whose target is a 07381 // template class as this may now be a template instance 07382 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); 07383 MemberName *fn; 07384 for (;(fn=fnli.current());++fnli) // for each global function name 07385 { 07386 MemberNameIterator fni(*fn); 07387 MemberDef *fmd; 07388 for (;(fmd=fni.current());++fni) // for each function with that name 07389 { 07390 if (fmd->isTypedefValCached()) 07391 { 07392 ClassDef *cd = fmd->getCachedTypedefVal(); 07393 if (cd->isTemplate()) fmd->invalidateTypedefValCache(); 07394 } 07395 } 07396 } 07397 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); 07398 for (;(fn=mnli.current());++mnli) // for each class method name 07399 { 07400 MemberNameIterator mni(*fn); 07401 MemberDef *fmd; 07402 for (;(fmd=mni.current());++mni) // for each function with that name 07403 { 07404 if (fmd->isTypedefValCached()) 07405 { 07406 ClassDef *cd = fmd->getCachedTypedefVal(); 07407 if (cd->isTemplate()) fmd->invalidateTypedefValCache(); 07408 } 07409 } 07410 } 07411 } 07412 07413 //---------------------------------------------------------------------------- 07414 07415 static void flushUnresolvedRelations() 07416 { 07417 // Remove all unresolved references to classes from the cache. 07418 // This is needed before resolving the inheritance relations, since 07419 // it would otherwise not find the inheritance relation 07420 // for C in the example below, as B::I was already found to be unresolvable 07421 // (which is correct if you igore the inheritance relation between A and B). 07422 // 07423 // class A { class I {} }; 07424 // class B : public A {}; 07425 // class C : public B::I {}; 07426 // 07427 QCacheIterator<LookupInfo> ci(Doxygen::lookupCache); 07428 LookupInfo *li=0; 07429 for (ci.toFirst();(li=ci.current());++ci) 07430 { 07431 if (li->classDef==0 && li->typeDef==0) 07432 { 07433 Doxygen::lookupCache.remove(ci.currentKey()); 07434 } 07435 } 07436 } 07437 07438 //---------------------------------------------------------------------------- 07439 07440 static void findDefineDocumentation(EntryNav *rootNav) 07441 { 07442 if ((rootNav->section()==Entry::DEFINEDOC_SEC || 07443 rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty() 07444 ) 07445 { 07446 rootNav->loadEntry(g_storage); 07447 Entry *root = rootNav->entry(); 07448 07449 //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n", 07450 // root->name.data(),root->args.data(),root->brief.data(),root->doc.data()); 07451 07452 if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file 07453 { 07454 MemberDef *md=new MemberDef("<tagfile>",1, 07455 "#define",root->name,root->args,0, 07456 Public,Normal,FALSE,FALSE,MemberDef::Define,0,0); 07457 md->setTagInfo(rootNav->tagInfo()); 07458 //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd); 07459 md->setFileDef(rootNav->parent()->fileDef()); 07460 //printf("Adding member=%s\n",md->name().data()); 07461 MemberName *mn; 07462 if ((mn=Doxygen::functionNameSDict->find(root->name))) 07463 { 07464 mn->append(md); 07465 } 07466 else 07467 { 07468 mn = new MemberName(root->name); 07469 mn->append(md); 07470 Doxygen::functionNameSDict->append(root->name,mn); 07471 } 07472 } 07473 MemberName *mn=Doxygen::functionNameSDict->find(root->name); 07474 if (mn) 07475 { 07476 int count=0; 07477 MemberDef *md=mn->first(); 07478 while (md) 07479 { 07480 if (md->memberType()==MemberDef::Define) count++; 07481 md=mn->next(); 07482 } 07483 if (count==1) 07484 { 07485 md=mn->first(); 07486 while (md) 07487 { 07488 if (md->memberType()==MemberDef::Define) 07489 { 07490 #if 0 07491 if (md->documentation().isEmpty()) 07492 #endif 07493 { 07494 md->setDocumentation(root->doc,root->docFile,root->docLine); 07495 md->setDocsForDefinition(!root->proto); 07496 } 07497 #if 0 07498 if (md->briefDescription().isEmpty()) 07499 #endif 07500 { 07501 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 07502 } 07503 if (md->inbodyDocumentation().isEmpty()) 07504 { 07505 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 07506 } 07507 md->setBodySegment(root->bodyLine,root->endBodyLine); 07508 md->setBodyDef(rootNav->fileDef()); 07509 md->addSectionsToDefinition(root->anchors); 07510 md->setMaxInitLines(root->initLines); 07511 md->setRefItems(root->sli); 07512 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId); 07513 addMemberToGroups(root,md); 07514 } 07515 md=mn->next(); 07516 } 07517 } 07518 else if (count>1 && 07519 (!root->doc.isEmpty() || 07520 !root->brief.isEmpty() || 07521 root->bodyLine!=-1 07522 ) 07523 ) 07524 // multiple defines don't know where to add docs 07525 // but maybe they are in different files together with their documentation 07526 { 07527 md=mn->first(); 07528 while (md) 07529 { 07530 if (md->memberType()==MemberDef::Define) 07531 { 07532 FileDef *fd=md->getFileDef(); 07533 if (fd && fd->absFilePath()==root->fileName) 07534 // doc and define in the same file assume they belong together. 07535 { 07536 #if 0 07537 if (md->documentation().isEmpty()) 07538 #endif 07539 { 07540 md->setDocumentation(root->doc,root->docFile,root->docLine); 07541 md->setDocsForDefinition(!root->proto); 07542 } 07543 #if 0 07544 if (md->briefDescription().isEmpty()) 07545 #endif 07546 { 07547 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); 07548 } 07549 if (md->inbodyDocumentation().isEmpty()) 07550 { 07551 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); 07552 } 07553 md->setBodySegment(root->bodyLine,root->endBodyLine); 07554 md->setBodyDef(rootNav->fileDef()); 07555 md->addSectionsToDefinition(root->anchors); 07556 md->setRefItems(root->sli); 07557 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId); 07558 addMemberToGroups(root,md); 07559 } 07560 } 07561 md=mn->next(); 07562 } 07563 //warn("Warning: define %s found in the following files:\n",root->name.data()); 07564 //warn("Cannot determine where to add the documentation found " 07565 // "at line %d of file %s. \n", 07566 // root->startLine,root->fileName.data()); 07567 } 07568 } 07569 else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found 07570 { 07571 static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING"); 07572 if (preEnabled) 07573 { 07574 warn(root->fileName,root->startLine, 07575 "Warning: documentation for unknown define %s found.\n", 07576 root->name.data() 07577 ); 07578 } 07579 else 07580 { 07581 warn(root->fileName,root->startLine, 07582 "Warning: found documented #define but ignoring it because " 07583 "ENABLE_PREPROCESSING is NO.\n", 07584 root->name.data() 07585 ); 07586 } 07587 } 07588 07589 rootNav->releaseEntry(); 07590 } 07591 RECURSE_ENTRYTREE(findDefineDocumentation,rootNav); 07592 } 07593 07594 //---------------------------------------------------------------------------- 07595 07596 static void findDirDocumentation(EntryNav *rootNav) 07597 { 07598 if (rootNav->section() == Entry::DIRDOC_SEC) 07599 { 07600 rootNav->loadEntry(g_storage); 07601 Entry *root = rootNav->entry(); 07602 07603 QCString normalizedName = root->name; 07604 normalizedName = substitute(normalizedName,"\\","/"); 07605 if (normalizedName.at(normalizedName.length()-1)!='/') 07606 { 07607 normalizedName+='/'; 07608 } 07609 DirDef *dir,*matchingDir=0; 07610 SDict<DirDef>::Iterator sdi(*Doxygen::directories); 07611 for (sdi.toFirst();(dir=sdi.current());++sdi) 07612 { 07613 //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data()); 07614 if (dir->name().right(normalizedName.length())==normalizedName) 07615 { 07616 if (matchingDir) 07617 { 07618 warn(root->fileName,root->startLine, 07619 "Warning: \\dir command matches multiple directories.\n" 07620 " Applying the command for directory %s\n" 07621 " Ignoring the command for directory %s\n", 07622 matchingDir->name().data(),dir->name().data() 07623 ); 07624 } 07625 else 07626 { 07627 matchingDir=dir; 07628 } 07629 } 07630 } 07631 if (matchingDir) 07632 { 07633 //printf("Match for with dir %s\n",matchingDir->name().data()); 07634 matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine); 07635 matchingDir->setDocumentation(root->doc,root->docFile,root->docLine); 07636 addDirToGroups(root,matchingDir); 07637 } 07638 else 07639 { 07640 warn(root->fileName,root->startLine,"Warning: No matching " 07641 "directory found for command \\dir %s\n",root->name.data()); 07642 } 07643 rootNav->releaseEntry(); 07644 } 07645 RECURSE_ENTRYTREE(findDirDocumentation,rootNav); 07646 } 07647 07648 07649 //---------------------------------------------------------------------------- 07650 // create a (sorted) list of separate documentation pages 07651 07652 static void buildPageList(EntryNav *rootNav) 07653 { 07654 if (rootNav->section() == Entry::PAGEDOC_SEC) 07655 { 07656 rootNav->loadEntry(g_storage); 07657 Entry *root = rootNav->entry(); 07658 07659 if (!root->name.isEmpty()) 07660 { 07661 addRelatedPage(rootNav); 07662 } 07663 07664 rootNav->releaseEntry(); 07665 } 07666 else if (rootNav->section() == Entry::MAINPAGEDOC_SEC) 07667 { 07668 rootNav->loadEntry(g_storage); 07669 Entry *root = rootNav->entry(); 07670 07671 QCString title=root->args.stripWhiteSpace(); 07672 if (title.isEmpty()) title=theTranslator->trMainPage(); 07673 addRefItem(root->sli,"page", 07674 Config_getBool("GENERATE_TREEVIEW")?"main":"index", 07675 title 07676 ); 07677 07678 rootNav->releaseEntry(); 07679 } 07680 RECURSE_ENTRYTREE(buildPageList,rootNav); 07681 } 07682 07683 static void findMainPage(EntryNav *rootNav) 07684 { 07685 if (rootNav->section() == Entry::MAINPAGEDOC_SEC) 07686 { 07687 rootNav->loadEntry(g_storage); 07688 Entry *root = rootNav->entry(); 07689 07690 if (Doxygen::mainPage==0) 07691 { 07692 //printf("Found main page! \n======\n%s\n=======\n",root->doc.data()); 07693 QCString title=root->args.stripWhiteSpace(); 07694 QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index"; 07695 Doxygen::mainPage = new PageDef(root->fileName,root->startLine, 07696 indexName, root->brief+root->doc,title); 07697 //setFileNameForSections(root->anchors,"index",Doxygen::mainPage); 07698 Doxygen::mainPage->setFileName(indexName); 07699 addPageToContext(Doxygen::mainPage,rootNav); 07700 07701 // a page name is a label as well! 07702 SectionInfo *si=new SectionInfo( 07703 indexName, 07704 Doxygen::mainPage->name(), 07705 Doxygen::mainPage->title(), 07706 SectionInfo::Section); 07707 Doxygen::sectionDict.insert(indexName,si); 07708 Doxygen::mainPage->addSectionsToDefinition(root->anchors); 07709 } 07710 else 07711 { 07712 warn(root->fileName,root->startLine, 07713 "Warning: found more than one \\mainpage comment block! Skipping this " 07714 "block." 07715 ); 07716 } 07717 07718 rootNav->releaseEntry(); 07719 } 07720 RECURSE_ENTRYTREE(findMainPage,rootNav); 07721 } 07722 07723 static void computePageRelations(EntryNav *rootNav) 07724 { 07725 if ((rootNav->section()==Entry::PAGEDOC_SEC || 07726 rootNav->section()==Entry::MAINPAGEDOC_SEC 07727 ) 07728 && !rootNav->name().isEmpty() 07729 ) 07730 { 07731 rootNav->loadEntry(g_storage); 07732 Entry *root = rootNav->entry(); 07733 07734 PageDef *pd = root->section==Entry::PAGEDOC_SEC ? 07735 Doxygen::pageSDict->find(root->name) : 07736 Doxygen::mainPage; 07737 if (pd) 07738 { 07739 QListIterator<BaseInfo> bii(*root->extends); 07740 BaseInfo *bi; 07741 for (bii.toFirst();(bi=bii.current());++bii) 07742 { 07743 PageDef *subPd = Doxygen::pageSDict->find(bi->name); 07744 if (subPd) 07745 { 07746 pd->addInnerCompound(subPd); 07747 //printf("*** Added subpage relation: %s->%s\n", 07748 // pd->name().data(),subPd->name().data()); 07749 } 07750 } 07751 } 07752 07753 rootNav->releaseEntry(); 07754 } 07755 RECURSE_ENTRYTREE(computePageRelations,rootNav); 07756 } 07757 07758 static void checkPageRelations() 07759 { 07760 PageSDict::Iterator pdi(*Doxygen::pageSDict); 07761 PageDef *pd=0; 07762 for (pdi.toFirst();(pd=pdi.current());++pdi) 07763 { 07764 Definition *ppd = pd->getOuterScope(); 07765 while (ppd) 07766 { 07767 if (ppd==pd) 07768 { 07769 err("Warning: page defined at line %d of file %s with label %s is a subpage " 07770 "of itself! Please remove this cyclic dependency.\n", 07771 pd->docLine(),pd->docFile().data(),pd->name().data()); 07772 exit(1); 07773 } 07774 ppd=ppd->getOuterScope(); 07775 } 07776 } 07777 } 07778 07779 //---------------------------------------------------------------------------- 07780 07781 static void resolveUserReferences() 07782 { 07783 QDictIterator<SectionInfo> sdi(Doxygen::sectionDict); 07784 SectionInfo *si; 07785 for (;(si=sdi.current());++sdi) 07786 { 07787 //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n", 07788 // si->label.data(),si->definition?si->definition->name().data():"<none>", 07789 // si->fileName.data()); 07790 PageDef *pd=0; 07791 07792 // hack: the items of a todo/test/bug/deprecated list are all fragments from 07793 // different files, so the resulting section's all have the wrong file 07794 // name (not from the todo/test/bug/deprecated list, but from the file in 07795 // which they are defined). We correct this here by looking at the 07796 // generated section labels! 07797 QDictIterator<RefList> rli(*Doxygen::xrefLists); 07798 RefList *rl; 07799 for (rli.toFirst();(rl=rli.current());++rli) 07800 { 07801 QCString label="_"+rl->listName(); // "_todo", "_test", ... 07802 if (si->label.left(label.length())==label) 07803 { 07804 si->fileName=rl->listName(); 07805 si->generated=TRUE; 07806 break; 07807 } 07808 } 07809 07810 //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data()); 07811 if (!si->generated) 07812 { 07813 // if this section is in a page and the page is in a group, then we 07814 // have to adjust the link file name to point to the group. 07815 if (!si->fileName.isEmpty() && 07816 (pd=Doxygen::pageSDict->find(si->fileName)) && 07817 pd->getGroupDef()) 07818 { 07819 si->fileName=pd->getGroupDef()->getOutputFileBase().copy(); 07820 } 07821 07822 if (si->definition) 07823 { 07824 // TODO: there should be one function in Definition that returns 07825 // the file to link to, so we can avoid the following tests. 07826 GroupDef *gd=0; 07827 if (si->definition->definitionType()==Definition::TypeMember) 07828 { 07829 gd = ((MemberDef *)si->definition)->getGroupDef(); 07830 } 07831 07832 if (gd) 07833 { 07834 si->fileName=gd->getOutputFileBase().copy(); 07835 } 07836 else 07837 { 07838 //si->fileName=si->definition->getOutputFileBase().copy(); 07839 //printf("Setting si->fileName to %s\n",si->fileName.data()); 07840 } 07841 } 07842 } 07843 //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data()); 07844 } 07845 } 07846 07847 07848 //---------------------------------------------------------------------------- 07849 // generate all separate documentation pages 07850 07851 07852 static void generatePageDocs() 07853 { 07854 //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count()); 07855 if (documentedPages==0) return; 07856 PageSDict::Iterator pdi(*Doxygen::pageSDict); 07857 PageDef *pd=0; 07858 for (pdi.toFirst();(pd=pdi.current());++pdi) 07859 { 07860 if (!pd->getGroupDef() && !pd->isReference()) 07861 { 07862 msg("Generating docs for page %s...\n",pd->name().data()); 07863 Doxygen::insideMainPage=TRUE; 07864 pd->writeDocumentation(*outputList); 07865 Doxygen::insideMainPage=FALSE; 07866 } 07867 } 07868 } 07869 07870 //---------------------------------------------------------------------------- 07871 // create a (sorted) list & dictionary of example pages 07872 07873 static void buildExampleList(EntryNav *rootNav) 07874 { 07875 if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) 07876 { 07877 rootNav->loadEntry(g_storage); 07878 Entry *root = rootNav->entry(); 07879 07880 if (Doxygen::exampleSDict->find(root->name)) 07881 { 07882 warn(root->fileName,root->startLine, 07883 "Warning: Example %s was already documented. Ignoring " 07884 "documentation found here.", 07885 root->name.data() 07886 ); 07887 } 07888 else 07889 { 07890 PageDef *pd=new PageDef(root->fileName,root->startLine, 07891 root->name,root->brief+root->doc,root->args); 07892 pd->setFileName(convertNameToFile(pd->name()+"-example")); 07893 pd->addSectionsToDefinition(root->anchors); 07894 //pi->addSections(root->anchors); 07895 07896 Doxygen::exampleSDict->inSort(root->name,pd); 07897 //we don't add example to groups 07898 //addExampleToGroups(root,pd); 07899 } 07900 07901 rootNav->releaseEntry(); 07902 } 07903 RECURSE_ENTRYTREE(buildExampleList,rootNav); 07904 } 07905 07906 //---------------------------------------------------------------------------- 07907 // prints the Entry tree (for debugging) 07908 07909 void printNavTree(EntryNav *rootNav,int indent) 07910 { 07911 QCString indentStr; 07912 indentStr.fill(' ',indent); 07913 msg("%s%s (sec=0x%x)\n", 07914 indentStr.isEmpty()?"":indentStr.data(), 07915 rootNav->name().isEmpty()?"<empty>":rootNav->name().data(), 07916 rootNav->section()); 07917 if (rootNav->children()) 07918 { 07919 EntryNavListIterator eli(*rootNav->children()); 07920 for (;eli.current();++eli) printNavTree(eli.current(),indent+2); 07921 } 07922 } 07923 07924 07925 //---------------------------------------------------------------------------- 07926 // generate the example documentation 07927 07928 static void generateExampleDocs() 07929 { 07930 outputList->disable(OutputGenerator::Man); 07931 PageSDict::Iterator pdi(*Doxygen::exampleSDict); 07932 PageDef *pd=0; 07933 for (pdi.toFirst();(pd=pdi.current());++pdi) 07934 { 07935 msg("Generating docs for example %s...\n",pd->name().data()); 07936 resetCCodeParserState(); 07937 QCString n=pd->getOutputFileBase(); 07938 startFile(*outputList,n,n,pd->name()); 07939 startTitle(*outputList,n); 07940 outputList->docify(pd->name()); 07941 endTitle(*outputList,n,0); 07942 outputList->parseDoc(pd->docFile(), // file 07943 pd->docLine(), // startLine 07944 pd, // context 07945 0, // memberDef 07946 pd->documentation()+"\n\n\\include "+pd->name(), // docs 07947 TRUE, // index words 07948 TRUE, // is example 07949 pd->name() 07950 ); 07951 endFile(*outputList); 07952 } 07953 outputList->enable(OutputGenerator::Man); 07954 } 07955 07956 //---------------------------------------------------------------------------- 07957 // generate module pages 07958 07959 static void generateGroupDocs() 07960 { 07961 GroupSDict::Iterator gli(*Doxygen::groupSDict); 07962 GroupDef *gd; 07963 for (gli.toFirst();(gd=gli.current());++gli) 07964 { 07965 if (!gd->isReference()) 07966 { 07967 gd->writeDocumentation(*outputList); 07968 } 07969 } 07970 } 07971 07972 //---------------------------------------------------------------------------- 07973 07974 //static void generatePackageDocs() 07975 //{ 07976 // writePackageIndex(*outputList); 07977 // 07978 // if (Doxygen::packageDict.count()>0) 07979 // { 07980 // PackageSDict::Iterator pdi(Doxygen::packageDict); 07981 // PackageDef *pd; 07982 // for (pdi.toFirst();(pd=pdi.current());++pdi) 07983 // { 07984 // pd->writeDocumentation(*outputList); 07985 // } 07986 // } 07987 //} 07988 07989 //---------------------------------------------------------------------------- 07990 // generate module pages 07991 07992 static void generateNamespaceDocs() 07993 { 07994 writeNamespaceIndex(*outputList); 07995 07996 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); 07997 NamespaceDef *nd; 07998 // for each namespace... 07999 for (;(nd=nli.current());++nli) 08000 { 08001 if (nd->isLinkableInProject()) 08002 { 08003 msg("Generating docs for namespace %s\n",nd->name().data()); 08004 nd->writeDocumentation(*outputList); 08005 } 08006 // for each class in the namespace... 08007 ClassSDict::Iterator cli(*nd->getClassSDict()); 08008 for ( ; cli.current() ; ++cli ) 08009 { 08010 ClassDef *cd=cli.current(); 08011 if ( ( cd->isLinkableInProject() && 08012 cd->templateMaster()==0 08013 ) // skip external references, anonymous compounds and 08014 // template instances and nested classes 08015 && !cd->isHidden() 08016 ) 08017 { 08018 msg("Generating docs for compound %s...\n",cd->name().data()); 08019 08020 cd->writeDocumentation(*outputList); 08021 cd->writeMemberList(*outputList); 08022 } 08023 cd->writeDocumentationForInnerClasses(*outputList); 08024 } 08025 } 08026 } 08027 08028 #if defined(_WIN32) 08029 static QCString fixSlashes(QCString &s) 08030 { 08031 QCString result; 08032 uint i; 08033 for (i=0;i<s.length();i++) 08034 { 08035 switch(s.at(i)) 08036 { 08037 case '/': 08038 case '\\': 08039 result+="\\\\"; 08040 break; 08041 default: 08042 result+=s.at(i); 08043 } 08044 } 08045 return result; 08046 } 08047 #endif 08048 08049 08050 //---------------------------------------------------------------------------- 08051 // generate files for the search engine 08052 08053 //static void generateSearchIndex() 08054 //{ 08055 // if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTML")) 08056 // { 08057 // // create search index 08058 // QCString fileName; 08059 // writeSearchButton(Config_getString("HTML_OUTPUT")); 08060 // 08061 //#if !defined(_WIN32) 08062 // // create cgi script 08063 // fileName = Config_getString("HTML_OUTPUT")+"/"+Config_getString("CGI_NAME"); 08064 // QFile f(fileName); 08065 // if (f.open(IO_WriteOnly)) 08066 // { 08067 // QTextStream t(&f); 08068 // t << "#!/bin/sh" << endl 08069 // << "DOXYSEARCH=" << Config_getString("BIN_ABSPATH") << "/doxysearch" << endl 08070 // << "DOXYPATH=\"" << Config_getString("DOC_ABSPATH") << " "; 08071 // 08072 // QStrList &extDocPaths=Config_getList("EXT_DOC_PATHS"); 08073 // char *s= extDocPaths.first(); 08074 // while (s) 08075 // { 08076 // t << s << " "; 08077 // s=extDocPaths.next(); 08078 // } 08079 // 08080 // t << "\"" << endl 08081 // << "if [ -f $DOXYSEARCH ]" << endl 08082 // << "then" << endl 08083 // << " $DOXYSEARCH $DOXYPATH" << endl 08084 // << "else" << endl 08085 // << " echo \"Content-Type: text/html\"" << endl 08086 // << " echo \"\"" << endl 08087 // << " echo \"<h2>Error: $DOXYSEARCH not found. Check cgi script!</h2>\"" << endl 08088 // << "fi" << endl; 08089 // 08090 // f.close(); 08091 // struct stat stat_struct; 08092 // stat(fileName,&stat_struct); 08093 // chmod(fileName,stat_struct.st_mode|S_IXUSR|S_IXGRP|S_IXOTH); 08094 // } 08095 // else 08096 // { 08097 // err("Error: Cannot open file %s for writing\n",fileName.data()); 08098 // } 08099 //#else /* Windows platform */ 08100 // // create cgi program 08101 // fileName = Config_getString("CGI_NAME").copy(); 08102 // if (fileName.right(4)==".cgi") 08103 // fileName=fileName.left(fileName.length()-4); 08104 // fileName+=".c"; 08105 // fileName.prepend(Config_getString("HTML_OUTPUT")+"/"); 08106 // QFile f(fileName); 08107 // if (f.open(IO_WriteOnly)) 08108 // { 08109 // QTextStream t(&f); 08110 // t << "#include <stdio.h>" << endl; 08111 // t << "#include <stdlib.h>" << endl; 08112 // t << "#include <process.h>" << endl; 08113 // t << endl; 08114 // t << "const char *DOXYSEARCH = \"" << 08115 // fixSlashes(Config_getString("BIN_ABSPATH")) << "\\\\doxysearch.exe\";" << endl; 08116 // t << "const char *DOXYPATH = \"" << 08117 // fixSlashes(Config_getString("DOC_ABSPATH")) << "\";" << endl; 08118 // t << endl; 08119 // t << "int main(void)" << endl; 08120 // t << "{" << endl; 08121 // t << " char buf[1024];" << endl; 08122 // t << " sprintf(buf,\"%s %s\",DOXYSEARCH,DOXYPATH);" << endl; 08123 // t << " if (system(buf))" << endl; 08124 // t << " {" << endl; 08125 // t << " printf(\"Content-Type: text/html\\n\\n\");" << endl; 08126 // t << " printf(\"<h2>Error: failed to execute %s</h2>\\n\",DOXYSEARCH);" << endl; 08127 // t << " exit(1);" << endl; 08128 // t << " }" << endl; 08129 // t << " return 0;" << endl; 08130 // t << "}" << endl; 08131 // f.close(); 08132 // } 08133 // else 08134 // { 08135 // err("Error: Cannot open file %s for writing\n",fileName.data()); 08136 // } 08137 //#endif /* !defined(_WIN32) */ 08138 // 08139 // // create config file 08140 // fileName = Config_getString("HTML_OUTPUT")+"/search.cfg"; 08141 // f.setName(fileName); 08142 // if (f.open(IO_WriteOnly)) 08143 // { 08144 // QTextStream t(&f); 08145 // t << Config_getString("DOC_URL") << "/" << endl 08146 // << Config_getString("CGI_URL") << "/" << Config_getString("CGI_NAME") << endl; 08147 // f.close(); 08148 // } 08149 // else 08150 // { 08151 // err("Error: Cannot open file %s for writing\n",fileName.data()); 08152 // } 08153 // //outputList->generateExternalIndex(); 08154 // outputList->pushGeneratorState(); 08155 // outputList->disableAllBut(OutputGenerator::Html); 08156 // startFile(*outputList,"header"+Doxygen::htmlFileExtension,0,"Search Engine",TRUE); 08157 // outputList->endPlainFile(); 08158 // outputList->startPlainFile("footer"+Doxygen::htmlFileExtension); 08159 // endFile(*outputList,TRUE); 08160 // outputList->popGeneratorState(); 08161 // } 08162 //} 08163 08164 //---------------------------------------------------------------------------- 08165 08166 static bool openOutputFile(const char *outFile,QFile &f) 08167 { 08168 bool fileOpened=FALSE; 08169 bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0'); 08170 if (writeToStdout) // write to stdout 08171 { 08172 fileOpened = f.open(IO_WriteOnly,stdout); 08173 } 08174 else // write to file 08175 { 08176 QFileInfo fi(outFile); 08177 if (fi.exists()) // create a backup 08178 { 08179 QDir dir=fi.dir(); 08180 QFileInfo backup(fi.fileName()+".bak"); 08181 if (backup.exists()) // remove existing backup 08182 dir.remove(backup.fileName()); 08183 dir.rename(fi.fileName(),fi.fileName()+".bak"); 08184 } 08185 f.setName(outFile); 08186 fileOpened = f.open(IO_WriteOnly|IO_Translate); 08187 } 08188 return fileOpened; 08189 } 08190 08195 static void generateConfigFile(const char *configFile,bool shortList, 08196 bool updateOnly=FALSE) 08197 { 08198 QFile f; 08199 bool fileOpened=openOutputFile(configFile,f); 08200 bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0'); 08201 if (fileOpened) 08202 { 08203 QTextStream t(&f); 08204 t.setEncoding(QTextStream::UnicodeUTF8); 08205 Config::instance()->writeTemplate(t,shortList,updateOnly); 08206 if (!writeToStdout) 08207 { 08208 if (!updateOnly) 08209 { 08210 msg("\n\nConfiguration file `%s' created.\n\n",configFile); 08211 msg("Now edit the configuration file and enter\n\n"); 08212 if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile")) 08213 msg(" doxygen %s\n\n",configFile); 08214 else 08215 msg(" doxygen\n\n"); 08216 msg("to generate the documentation for your project\n\n"); 08217 } 08218 else 08219 { 08220 msg("\n\nConfiguration file `%s' updated.\n\n",configFile); 08221 } 08222 } 08223 } 08224 else 08225 { 08226 err("Error: Cannot open file %s for writing\n",configFile); 08227 exit(1); 08228 } 08229 } 08230 08231 //---------------------------------------------------------------------------- 08232 // read and parse a tag file 08233 08234 //static bool readLineFromFile(QFile &f,QCString &s) 08235 //{ 08236 // char c=0; 08237 // s.resize(0); 08238 // while (!f.atEnd() && (c=f.getch())!='\n') s+=c; 08239 // return f.atEnd(); 08240 //} 08241 08242 //---------------------------------------------------------------------------- 08243 08244 static void readTagFile(Entry *root,const char *tl) 08245 { 08246 QCString tagLine = tl; 08247 QCString fileName; 08248 QCString destName; 08249 int eqPos = tagLine.find('='); 08250 if (eqPos!=-1) // tag command contains a destination 08251 { 08252 fileName = tagLine.left(eqPos).stripWhiteSpace(); 08253 destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace(); 08254 QFileInfo fi(fileName); 08255 Doxygen::tagDestinationDict.insert(fi.fileName(),new QCString(destName)); 08256 //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data()); 08257 } 08258 else 08259 { 08260 fileName = tagLine; 08261 } 08262 08263 QFileInfo fi(fileName); 08264 if (!fi.exists() || !fi.isFile()) 08265 { 08266 err("Error: Tag file `%s' does not exist or is not a file. Skipping it...\n", 08267 fileName.data()); 08268 return; 08269 } 08270 08271 if (!destName.isEmpty()) 08272 msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data()); 08273 else 08274 msg("Reading tag file `%s'...\n",fileName.data()); 08275 08276 parseTagFile(root,fi.absFilePath(),fi.fileName()); 08277 08278 } 08279 08280 //---------------------------------------------------------------------------- 08281 // returns TRUE if the name of the file represented by `fi' matches 08282 // one of the file patterns in the `patList' list. 08283 08284 static bool patternMatch(QFileInfo *fi,QStrList *patList) 08285 { 08286 bool found=FALSE; 08287 if (patList) 08288 { 08289 QCString pattern=patList->first(); 08290 while (!pattern.isEmpty() && !found) 08291 { 08292 int i=pattern.find('='); 08293 if (i!=-1) pattern=pattern.left(i); // strip of the extension specific filter name 08294 08295 #if defined(_WIN32) // windows 08296 QRegExp re(pattern,FALSE,TRUE); // case insensitive match 08297 #else // unix 08298 QRegExp re(pattern,TRUE,TRUE); // case sensitive match 08299 #endif 08300 found = found || re.match(fi->fileName())!=-1 || 08301 re.match(fi->filePath())!=-1 || 08302 re.match(fi->absFilePath())!=-1; 08303 //printf("Matching `%s' against pattern `%s' found=%d\n", 08304 // fi->fileName().data(),pattern.data(),found); 08305 pattern=patList->next(); 08306 } 08307 } 08308 return found; 08309 } 08310 08311 static int transcodeCharacterBuffer(BufStr &srcBuf,int size, 08312 const char *inputEncoding,const char *outputEncoding) 08313 { 08314 if (inputEncoding==0 || outputEncoding==0) return size; 08315 if (qstricmp(inputEncoding,outputEncoding)==0) return size; 08316 void *cd = portable_iconv_open(outputEncoding,inputEncoding); 08317 if (cd==(void *)(-1)) 08318 { 08319 err("Error: unsupported character conversion: '%s'->'%s': %s\n" 08320 "Check the INPUT_ENCODING setting in the config file!\n", 08321 inputEncoding,outputEncoding,strerror(errno)); 08322 exit(1); 08323 } 08324 int tmpBufSize=size*4+1; 08325 BufStr tmpBuf(tmpBufSize); 08326 size_t iLeft=size; 08327 size_t oLeft=tmpBufSize; 08328 const char *srcPtr = srcBuf.data(); 08329 char *dstPtr = tmpBuf.data(); 08330 uint newSize=0; 08331 if (!portable_iconv(cd, &srcPtr, &iLeft, &dstPtr, &oLeft)) 08332 { 08333 newSize = tmpBufSize-oLeft; 08334 srcBuf.shrink(newSize); 08335 strncpy(srcBuf.data(),tmpBuf.data(),newSize); 08336 //printf("iconv: input size=%d output size=%d\n[%s]\n",size,newSize,srcBuf.data()); 08337 } 08338 else 08339 { 08340 err("Error: failed to translate characters from %s to %s: check INPUT_ENCODING\n", 08341 inputEncoding,outputEncoding); 08342 exit(1); 08343 } 08344 portable_iconv_close(cd); 08345 return newSize; 08346 } 08347 08348 //---------------------------------------------------------------------------- 08349 // reads a file into an array and filters out any 0x00 and 0x06 bytes, 08350 // because these are special for the parser. 08351 08352 void copyAndFilterFile(const char *fileName,BufStr &dest) 08353 { 08354 // try to open file 08355 int size=0; 08356 //uint oldPos = dest.curPos(); 08357 //printf(".......oldPos=%d\n",oldPos); 08358 08359 QFileInfo fi(fileName); 08360 if (!fi.exists()) return; 08361 QCString filterName = getFileFilter(fileName); 08362 if (filterName.isEmpty()) 08363 { 08364 QFile f(fileName); 08365 if (!f.open(IO_ReadOnly)) 08366 { 08367 err("Error: could not open file %s\n",fileName); 08368 return; 08369 } 08370 size=fi.size(); 08371 // read the file 08372 dest.skip(size); 08373 if (f.readBlock(dest.data()/*+oldPos*/,size)!=size) 08374 { 08375 err("Error while reading file %s\n",fileName); 08376 return; 08377 } 08378 } 08379 else 08380 { 08381 QCString cmd=filterName+" \""+fileName+"\""; 08382 Debug::print(Debug::ExtCmd,0,"Executing popen(`%s`)\n",cmd.data()); 08383 FILE *f=portable_popen(cmd,"r"); 08384 if (!f) 08385 { 08386 err("Error: could not execute filter %s\n",filterName.data()); 08387 return; 08388 } 08389 const int bufSize=1024; 08390 char buf[bufSize]; 08391 int numRead; 08392 while ((numRead=fread(buf,1,bufSize,f))>0) 08393 { 08394 //printf(">>>>>>>>Reading %d bytes\n",numRead); 08395 dest.addArray(buf,numRead),size+=numRead; 08396 } 08397 portable_pclose(f); 08398 } 08399 // filter unwanted bytes from the resulting data 08400 uchar conv[256]; 08401 int i; 08402 for (i=0;i<256;i++) conv[i]=i; 08403 conv[0x06]=0x20; // replace the offending characters with spaces 08404 conv[0x00]=0x20; 08405 // remove any special markers from the input 08406 uchar *p=(uchar *)dest.data()/*+oldPos*/; 08407 for (i=0;i<size;i++,p++) *p=conv[*p]; 08408 // and translate CR's 08409 int newSize=filterCRLF(dest.data()/*+oldPos*/,size); 08410 //printf("filter char at %p size=%d newSize=%d\n",dest.data()+oldPos,size,newSize); 08411 if (newSize!=size) // we removed chars 08412 { 08413 dest.shrink(/*oldPos+*/newSize); // resize the array 08414 //printf(".......resizing from %d to %d result=[%s]\n",oldPos+size,oldPos+newSize,dest.data()); 08415 } 08416 } 08417 08418 //---------------------------------------------------------------------------- 08419 static void copyStyleSheet() 08420 { 08421 QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET"); 08422 if (!htmlStyleSheet.isEmpty()) 08423 { 08424 QFile cssf(htmlStyleSheet); 08425 QFileInfo cssfi(htmlStyleSheet); 08426 if (cssf.open(IO_ReadOnly)) 08427 { 08428 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+cssfi.fileName().data(); 08429 QFile df(destFileName); 08430 if (df.open(IO_WriteOnly)) 08431 { 08432 char *buffer = new char[cssf.size()]; 08433 cssf.readBlock(buffer,cssf.size()); 08434 df.writeBlock(buffer,cssf.size()); 08435 df.flush(); 08436 delete[] buffer; 08437 } 08438 else 08439 { 08440 err("Error: could not write to style sheet %s\n",destFileName.data()); 08441 } 08442 } 08443 else 08444 { 08445 err("Error: could not open user specified style sheet %s\n",Config_getString("HTML_STYLESHEET").data()); 08446 htmlStyleSheet.resize(0); // revert to the default 08447 } 08448 } 08449 } 08450 08451 static void parseFiles(Entry *root,EntryNav *rootNav) 08452 { 08453 void *cd = 0; 08454 QCString inpEncoding = Config_getString("INPUT_ENCODING"); 08455 bool needsTranscoding = !inpEncoding.isEmpty(); 08456 if (needsTranscoding) 08457 { 08458 if (!(cd = portable_iconv_open("UTF-8", inpEncoding))) 08459 { 08460 err("Error: unsupported character enconding: '%s'",inpEncoding.data()); 08461 exit(1); 08462 } 08463 } 08464 08465 QCString *s=inputFiles.first(); 08466 while (s) 08467 { 08468 QCString fileName=*s; 08469 QCString extension; 08470 int ei = fileName.findRev('.'); 08471 if (ei!=-1) extension=fileName.right(fileName.length()-ei); 08472 ParserInterface *parser = Doxygen::parserManager->getParser(extension); 08473 08474 QFileInfo fi(fileName); 08475 BufStr preBuf(fi.size()+4096); 08476 //BufStr *bufPtr = &preBuf; 08477 08478 if (Config_getBool("ENABLE_PREPROCESSING") && 08479 parser->needsPreprocessing(extension)) 08480 { 08481 msg("Preprocessing %s...\n",s->data()); 08482 preprocessFile(fileName,preBuf); 08483 } 08484 else 08485 { 08486 msg("Reading %s...\n",s->data()); 08487 copyAndFilterFile(fileName,preBuf); 08488 } 08489 08490 preBuf.addChar('\n'); /* to prevent problems under Windows ? */ 08491 08492 // do character transcoding if needed. 08493 transcodeCharacterBuffer(preBuf,preBuf.curPos(), 08494 Config_getString("INPUT_ENCODING"),"UTF-8"); 08495 08496 BufStr convBuf(preBuf.curPos()+1024); 08497 08498 // convert multi-line C++ comments to C style comments 08499 convertCppComments(&preBuf,&convBuf,fileName); 08500 08501 convBuf.addChar('\0'); 08502 08503 // use language parse to parse the file 08504 parser->parseInput(fileName,convBuf.data(),root); 08505 08506 // store the Entry tree in a file and create an index to 08507 // navigate/load entries 08508 bool ambig; 08509 FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig); 08510 ASSERT(fd!=0); 08511 root->createNavigationIndex(rootNav,g_storage,fd); 08512 08513 s=inputFiles.next(); 08514 } 08515 } 08516 08517 08518 //---------------------------------------------------------------------------- 08519 // Read all files matching at least one pattern in `patList' in the 08520 // directory represented by `fi'. 08521 // The directory is read iff the recusiveFlag is set. 08522 // The contents of all files is append to the input string 08523 08524 int readDir(QFileInfo *fi, 08525 FileNameList *fnList, 08526 FileNameDict *fnDict, 08527 StringDict *exclDict, 08528 QStrList *patList, 08529 QStrList *exclPatList, 08530 StringList *resultList, 08531 StringDict *resultDict, 08532 bool errorIfNotExist, 08533 bool recursive, 08534 QDict<void> *killDict 08535 ) 08536 { 08537 QDir dir((const char *)fi->absFilePath()); 08538 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden ); 08539 int totalSize=0; 08540 msg("Searching for files in directory %s\n", fi->absFilePath().data()); 08541 //printf("killDict=%p count=%d\n",killDict,killDict->count()); 08542 08543 const QFileInfoList *list = dir.entryInfoList(); 08544 QFileInfoListIterator it( *list ); 08545 QFileInfo *cfi; 08546 08547 while ((cfi=it.current())) 08548 { 08549 if (exclDict==0 || exclDict->find(cfi->absFilePath())==0) 08550 { // file should not be excluded 08551 //printf("killDict->find(%s)\n",cfi->absFilePath().data()); 08552 if (!cfi->exists() || !cfi->isReadable()) 08553 { 08554 if (errorIfNotExist) 08555 { 08556 err("Warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data()); 08557 } 08558 } 08559 else if (cfi->isFile() && 08560 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) && 08561 (patList==0 || patternMatch(cfi,patList)) && 08562 !patternMatch(cfi,exclPatList) && 08563 (killDict==0 || killDict->find(cfi->absFilePath())==0) 08564 ) 08565 { 08566 totalSize+=cfi->size()+cfi->absFilePath().length()+4; 08567 QCString name=convertToQCString(cfi->fileName()); 08568 //printf("New file %s\n",name.data()); 08569 if (fnDict) 08570 { 08571 FileDef *fd=new FileDef(cfi->dirPath()+"/",name); 08572 FileName *fn=0; 08573 if (!name.isEmpty() && (fn=(*fnDict)[name])) 08574 { 08575 fn->append(fd); 08576 } 08577 else 08578 { 08579 fn = new FileName(cfi->absFilePath(),name); 08580 fn->append(fd); 08581 if (fnList) fnList->inSort(fn); 08582 fnDict->insert(name,fn); 08583 } 08584 } 08585 QCString *rs=0; 08586 if (resultList || resultDict) 08587 { 08588 rs=new QCString(cfi->absFilePath()); 08589 } 08590 if (resultList) resultList->append(rs); 08591 if (resultDict) resultDict->insert(cfi->absFilePath(),rs); 08592 if (killDict) killDict->insert(cfi->absFilePath(),(void *)0x8); 08593 } 08594 else if (recursive && 08595 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) && 08596 cfi->isDir() && cfi->fileName()!="." && 08597 !patternMatch(cfi,exclPatList) && 08598 cfi->fileName()!="..") 08599 { 08600 cfi->setFile(cfi->absFilePath()); 08601 totalSize+=readDir(cfi,fnList,fnDict,exclDict, 08602 patList,exclPatList,resultList,resultDict,errorIfNotExist, 08603 recursive,killDict); 08604 } 08605 } 08606 ++it; 08607 } 08608 return totalSize; 08609 } 08610 08611 08612 //---------------------------------------------------------------------------- 08613 // read a file or all files in a directory and append their contents to the 08614 // input string. The names of the files are appended to the `fiList' list. 08615 08616 int readFileOrDirectory(const char *s, 08617 FileNameList *fnList, 08618 FileNameDict *fnDict, 08619 StringDict *exclDict, 08620 QStrList *patList, 08621 QStrList *exclPatList, 08622 StringList *resultList, 08623 StringDict *resultDict, 08624 bool recursive, 08625 bool errorIfNotExist, 08626 QDict<void> *killDict 08627 ) 08628 { 08629 //printf("killDict=%p count=%d\n",killDict,killDict->count()); 08630 // strip trailing slashes 08631 if (s==0) return 0; 08632 QCString fs = s; 08633 char lc = fs.at(fs.length()-1); 08634 if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1); 08635 08636 QFileInfo fi(fs); 08637 //printf("readFileOrDirectory(%s)\n",s); 08638 int totalSize=0; 08639 { 08640 if (exclDict==0 || exclDict->find(fi.absFilePath())==0) 08641 { 08642 if (!fi.exists() || !fi.isReadable()) 08643 { 08644 if (errorIfNotExist) 08645 { 08646 err("Warning: source %s is not a readable file or directory... skipping.\n",s); 08647 } 08648 } 08649 else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink()) 08650 { 08651 if (fi.isFile()) 08652 { 08653 //printf("killDict->find(%s)\n",fi.absFilePath().data()); 08654 if (killDict==0 || killDict->find(fi.absFilePath())==0) 08655 { 08656 totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); 08657 //fiList->inSort(new FileInfo(fi)); 08658 QCString name=convertToQCString(fi.fileName()); 08659 //printf("New file %s\n",name.data()); 08660 if (fnDict) 08661 { 08662 FileDef *fd=new FileDef(fi.dirPath(TRUE)+"/",name); 08663 FileName *fn=0; 08664 if (!name.isEmpty() && (fn=(*fnDict)[name])) 08665 { 08666 fn->append(fd); 08667 } 08668 else 08669 { 08670 fn = new FileName(fi.absFilePath(),name); 08671 fn->append(fd); 08672 if (fnList) fnList->inSort(fn); 08673 fnDict->insert(name,fn); 08674 } 08675 } 08676 QCString *rs=0; 08677 if (resultList || resultDict) 08678 { 08679 rs=new QCString(fi.absFilePath()); 08680 if (resultList) resultList->append(rs); 08681 if (resultDict) resultDict->insert(fi.absFilePath(),rs); 08682 } 08683 08684 if (killDict) killDict->insert(fi.absFilePath(),(void *)0x8); 08685 } 08686 } 08687 else if (fi.isDir()) // readable dir 08688 { 08689 totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList, 08690 exclPatList,resultList,resultDict,errorIfNotExist, 08691 recursive,killDict); 08692 } 08693 } 08694 } 08695 } 08696 return totalSize; 08697 } 08698 08699 //---------------------------------------------------------------------------- 08700 08701 void readFormulaRepository() 08702 { 08703 QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository"); 08704 if (f.open(IO_ReadOnly)) // open repository 08705 { 08706 msg("Reading formula repository...\n"); 08707 QTextStream t(&f); 08708 QCString line; 08709 while (!t.eof()) 08710 { 08711 line=t.readLine(); 08712 int se=line.find(':'); // find name and text separator. 08713 if (se==-1) 08714 { 08715 err("Warning: formula.repository is corrupted!\n"); 08716 break; 08717 } 08718 else 08719 { 08720 QCString formName = line.left(se); 08721 QCString formText = line.right(line.length()-se-1); 08722 Formula *f=new Formula(formText); 08723 Doxygen::formulaList.append(f); 08724 Doxygen::formulaDict.insert(formText,f); 08725 Doxygen::formulaNameDict.insert(formName,f); 08726 } 08727 } 08728 } 08729 } 08730 08731 //---------------------------------------------------------------------------- 08732 08733 static void expandAliases() 08734 { 08735 QDictIterator<QCString> adi(Doxygen::aliasDict); 08736 QCString *s; 08737 for (adi.toFirst();(s=adi.current());++adi) 08738 { 08739 *s = expandAlias(adi.currentKey(),*s); 08740 } 08741 } 08742 08743 //---------------------------------------------------------------------------- 08744 08745 static void escapeAliases() 08746 { 08747 QDictIterator<QCString> adi(Doxygen::aliasDict); 08748 QCString *s; 08749 for (adi.toFirst();(s=adi.current());++adi) 08750 { 08751 QCString value=*s,newValue; 08752 int in,p=0; 08753 // for each \n in the alias command value 08754 while ((in=value.find("\\n",p))!=-1) 08755 { 08756 newValue+=value.mid(p,in-p); 08757 // expand \n's except if \n is part of a built-in command. 08758 if (value.mid(in,5)!="\\note" && 08759 value.mid(in,5)!="\\name" && 08760 value.mid(in,10)!="\\namespace" && 08761 value.mid(in,14)!="\\nosubgrouping" 08762 ) 08763 { 08764 newValue+="\\_linebr "; 08765 } 08766 else 08767 { 08768 newValue+="\\n"; 08769 } 08770 p=in+2; 08771 } 08772 newValue+=value.mid(p,value.length()-p); 08773 *s=newValue; 08774 //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data()); 08775 } 08776 } 08777 08778 //---------------------------------------------------------------------------- 08779 08780 void readAliases() 08781 { 08782 // add aliases to a dictionary 08783 Doxygen::aliasDict.setAutoDelete(TRUE); 08784 QStrList &aliasList = Config_getList("ALIASES"); 08785 const char *s=aliasList.first(); 08786 while (s) 08787 { 08788 if (Doxygen::aliasDict[s]==0) 08789 { 08790 QCString alias=s; 08791 int i=alias.find('='); 08792 if (i>0) 08793 { 08794 QCString name=alias.left(i).stripWhiteSpace(); 08795 QCString value=alias.right(alias.length()-i-1); 08796 //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); 08797 if (!name.isEmpty()) 08798 { 08799 QCString *dn=Doxygen::aliasDict[name]; 08800 if (dn==0) // insert new alias 08801 { 08802 Doxygen::aliasDict.insert(name,new QCString(value)); 08803 } 08804 else // overwrite previous alias 08805 { 08806 *dn=value; 08807 } 08808 } 08809 } 08810 } 08811 s=aliasList.next(); 08812 } 08813 expandAliases(); 08814 escapeAliases(); 08815 } 08816 08817 //---------------------------------------------------------------------------- 08818 08819 static void dumpSymbol(QTextStream &t,Definition *d) 08820 { 08821 QCString anchor; 08822 if (d->definitionType()==Definition::TypeMember) 08823 { 08824 MemberDef *md = (MemberDef *)d; 08825 anchor=":"+md->anchor(); 08826 } 08827 QCString scope; 08828 if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) 08829 { 08830 scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension; 08831 } 08832 t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('" 08833 << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','" 08834 << scope << "','" 08835 << d->name() << "','" 08836 << d->getDefFileName() << "','" 08837 << d->getDefLine() 08838 << "');" << endl; 08839 } 08840 08841 static void dumpSymbolMap() 08842 { 08843 QFile f("symbols.sql"); 08844 if (f.open(IO_WriteOnly)) 08845 { 08846 QTextStream t(&f); 08847 QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap); 08848 DefinitionIntf *intf; 08849 for (;(intf=di.current());++di) 08850 { 08851 if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols 08852 { 08853 DefinitionListIterator dli(*(DefinitionList*)intf); 08854 Definition *d; 08855 // for each symbol 08856 for (dli.toFirst();(d=dli.current());++dli) 08857 { 08858 dumpSymbol(t,d); 08859 } 08860 } 08861 else // single symbol 08862 { 08863 Definition *d = (Definition *)intf; 08864 if (d!=Doxygen::globalScope) dumpSymbol(t,d); 08865 } 08866 } 08867 } 08868 } 08869 08870 08871 //---------------------------------------------------------------------------- 08872 // print the usage of doxygen 08873 08874 static void usage(const char *name) 08875 { 08876 msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2008\n\n",versionString); 08877 msg("You can use doxygen in a number of ways:\n\n"); 08878 msg("1) Use doxygen to generate a template configuration file:\n"); 08879 msg(" %s [-s] -g [configName]\n\n",name); 08880 msg(" If - is used for configName doxygen will write to standard output.\n\n"); 08881 msg("2) Use doxygen to update an old configuration file:\n"); 08882 msg(" %s [-s] -u [configName]\n\n",name); 08883 msg("3) Use doxygen to generate documentation using an existing "); 08884 msg("configuration file:\n"); 08885 msg(" %s [configName]\n\n",name); 08886 msg(" If - is used for configName doxygen will read from standard input.\n\n"); 08887 msg("4) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n"); 08888 msg(" RTF: %s -w rtf styleSheetFile\n",name); 08889 msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name); 08890 msg(" LaTeX: %s -w latex headerFile styleSheetFile [configFile]\n\n",name); 08891 msg("5) Use doxygen to generate an rtf extensions file\n"); 08892 msg(" RTF: %s -e rtf extensionsFile\n\n",name); 08893 msg("If -s is specified the comments in the config file will be omitted.\n"); 08894 msg("If configName is omitted `Doxyfile' will be used as a default.\n\n"); 08895 exit(1); 08896 } 08897 08898 //---------------------------------------------------------------------------- 08899 // read the argument of option `c' from the comment argument list and 08900 // update the option index `optind'. 08901 08902 static const char *getArg(int argc,char **argv,int &optind) 08903 { 08904 char *s=0; 08905 if (strlen(&argv[optind][2])>0) 08906 s=&argv[optind][2]; 08907 else if (optind+1<argc && argv[optind+1][0]!='-') 08908 s=argv[++optind]; 08909 return s; 08910 } 08911 08912 //---------------------------------------------------------------------------- 08913 08914 extern void commentScanTest(); 08915 08916 void initDoxygen() 08917 { 08918 #if QT_VERSION >= 200 08919 setlocale(LC_ALL,""); 08920 setlocale(LC_NUMERIC,"C"); 08921 #endif 08922 08923 //Doxygen::symbolMap->setAutoDelete(TRUE); 08924 08925 Doxygen::runningTime.start(); 08926 initPreprocessor(); 08927 08928 ParserInterface *defaultParser = new CLanguageScanner; 08929 Doxygen::parserManager = new ParserManager(defaultParser); 08930 Doxygen::parserManager->registerParser(".py", new PythonLanguageScanner); 08931 Doxygen::parserManager->registerParser(".f", new FortranLanguageScanner); 08932 Doxygen::parserManager->registerParser(".f90", new FortranLanguageScanner); 08933 Doxygen::parserManager->registerParser(".vhd", new VHDLLanguageScanner); 08934 08935 08936 // register any additional parsers here... 08937 08938 08939 initClassMemberIndices(); 08940 initNamespaceMemberIndices(); 08941 initFileMemberIndices(); 08942 } 08943 08944 void cleanUpDoxygen() 08945 { 08946 delete Doxygen::inputNameDict; 08947 delete Doxygen::includeNameDict; 08948 delete Doxygen::exampleNameDict; 08949 delete Doxygen::imageNameDict; 08950 delete Doxygen::dotFileNameDict; 08951 delete Doxygen::mainPage; 08952 delete Doxygen::pageSDict; 08953 delete Doxygen::exampleSDict; 08954 delete Doxygen::globalScope; 08955 delete Doxygen::xrefLists; 08956 delete Doxygen::parserManager; 08957 cleanUpPreprocessor(); 08958 delete theTranslator; 08959 delete outputList; 08960 Mappers::freeMappers(); 08961 codeFreeScanner(); 08962 08963 if (Doxygen::symbolMap) 08964 { 08965 // iterate through Doxygen::symbolMap and delete all 08966 // DefinitionList objects, since they have no owner 08967 QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap); 08968 DefinitionIntf *di; 08969 for (dli.toFirst();(di=dli.current());) 08970 { 08971 if (di->definitionType()==DefinitionIntf::TypeSymbolList) 08972 { 08973 DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey()); 08974 delete (DefinitionList *)tmp; 08975 } 08976 else 08977 { 08978 ++dli; 08979 } 08980 } 08981 } 08982 08983 delete Doxygen::inputNameList; 08984 delete Doxygen::memberNameSDict; 08985 delete Doxygen::functionNameSDict; 08986 delete Doxygen::groupSDict; 08987 delete Doxygen::classSDict; 08988 delete Doxygen::hiddenClasses; 08989 delete Doxygen::namespaceSDict; 08990 delete Doxygen::directories; 08991 08992 //delete Doxygen::symbolMap; <- we cannot do this unless all static lists 08993 // (such as Doxygen::namespaceSDict) 08994 // with objects based on Definition are made 08995 // dynamic first 08996 } 08997 08998 void readConfiguration(int argc, char **argv) 08999 { 09000 /************************************************************************** 09001 * Handle arguments * 09002 **************************************************************************/ 09003 09004 int optind=1; 09005 const char *configName=0; 09006 const char *debugLabel; 09007 const char *formatName; 09008 bool genConfig=FALSE; 09009 bool shortList=FALSE; 09010 bool updateConfig=FALSE; 09011 while (optind<argc && argv[optind][0]=='-' && 09012 (isalpha(argv[optind][1]) || argv[optind][1]=='?' || 09013 argv[optind][1]=='-') 09014 ) 09015 { 09016 switch(argv[optind][1]) 09017 { 09018 case 'g': 09019 genConfig=TRUE; 09020 configName=getArg(argc,argv,optind); 09021 if (strcmp(argv[optind+1],"-")==0) 09022 { configName="-"; optind++; } 09023 if (!configName) 09024 { configName="Doxyfile"; } 09025 break; 09026 case 'd': 09027 debugLabel=getArg(argc,argv,optind); 09028 Debug::setFlag(debugLabel); 09029 break; 09030 case 's': 09031 shortList=TRUE; 09032 break; 09033 case 'u': 09034 updateConfig=TRUE; 09035 break; 09036 case 'e': 09037 formatName=getArg(argc,argv,optind); 09038 if (!formatName) 09039 { 09040 err("Error:option -e is missing format specifier rtf.\n"); 09041 cleanUpDoxygen(); 09042 exit(1); 09043 } 09044 if (stricmp(formatName,"rtf")==0) 09045 { 09046 if (optind+1>=argc) 09047 { 09048 err("Error: option \"-e rtf\" is missing an extensions file name\n"); 09049 cleanUpDoxygen(); 09050 exit(1); 09051 } 09052 QFile f; 09053 if (openOutputFile(argv[optind+1],f)) 09054 { 09055 RTFGenerator::writeExtensionsFile(f); 09056 } 09057 cleanUpDoxygen(); 09058 exit(1); 09059 } 09060 err("Error: option \"-e\" has invalid format specifier.\n"); 09061 cleanUpDoxygen(); 09062 exit(1); 09063 break; 09064 case 'w': 09065 formatName=getArg(argc,argv,optind); 09066 if (!formatName) 09067 { 09068 err("Error: option -w is missing format specifier rtf, html or latex\n"); 09069 cleanUpDoxygen(); 09070 exit(1); 09071 } 09072 if (stricmp(formatName,"rtf")==0) 09073 { 09074 if (optind+1>=argc) 09075 { 09076 err("Error: option \"-w rtf\" is missing a style sheet file name\n"); 09077 cleanUpDoxygen(); 09078 exit(1); 09079 } 09080 QFile f; 09081 if (openOutputFile(argv[optind+1],f)) 09082 { 09083 RTFGenerator::writeStyleSheetFile(f); 09084 } 09085 cleanUpDoxygen(); 09086 exit(1); 09087 } 09088 else if (stricmp(formatName,"html")==0) 09089 { 09090 if (optind+4<argc) 09091 { 09092 if (!Config::instance()->parse(argv[optind+4])) 09093 { 09094 err("Error opening or reading configuration file %s!\n",argv[optind+4]); 09095 cleanUpDoxygen(); 09096 exit(1); 09097 } 09098 Config::instance()->substituteEnvironmentVars(); 09099 Config::instance()->convertStrToVal(); 09100 Config::instance()->check(); 09101 } 09102 else 09103 { 09104 Config::instance()->init(); 09105 } 09106 if (optind+3>=argc) 09107 { 09108 err("Error: option \"-w html\" does not have enough arguments\n"); 09109 cleanUpDoxygen(); 09110 exit(1); 09111 } 09112 09113 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); 09114 if (!setTranslator(outputLanguage)) 09115 { 09116 err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data()); 09117 } 09118 09119 QFile f; 09120 if (openOutputFile(argv[optind+1],f)) 09121 { 09122 HtmlGenerator::writeHeaderFile(f); 09123 } 09124 f.close(); 09125 if (openOutputFile(argv[optind+2],f)) 09126 { 09127 HtmlGenerator::writeFooterFile(f); 09128 } 09129 f.close(); 09130 if (openOutputFile(argv[optind+3],f)) 09131 { 09132 HtmlGenerator::writeStyleSheetFile(f); 09133 } 09134 cleanUpDoxygen(); 09135 exit(0); 09136 } 09137 else if (stricmp(formatName,"latex")==0) 09138 { 09139 if (optind+3<argc) // use config file to get settings 09140 { 09141 if (!Config::instance()->parse(argv[optind+3])) 09142 { 09143 err("Error opening or reading configuration file %s!\n",argv[optind+3]); 09144 exit(1); 09145 } 09146 Config::instance()->substituteEnvironmentVars(); 09147 Config::instance()->convertStrToVal(); 09148 Config::instance()->check(); 09149 } 09150 else // use default config 09151 { 09152 Config::instance()->init(); 09153 } 09154 if (optind+2>=argc) 09155 { 09156 err("Error: option \"-w latex\" does not have enough arguments\n"); 09157 cleanUpDoxygen(); 09158 exit(1); 09159 } 09160 09161 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); 09162 if (!setTranslator(outputLanguage)) 09163 { 09164 err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data()); 09165 } 09166 09167 QFile f; 09168 if (openOutputFile(argv[optind+1],f)) 09169 { 09170 LatexGenerator::writeHeaderFile(f); 09171 } 09172 f.close(); 09173 if (openOutputFile(argv[optind+2],f)) 09174 { 09175 LatexGenerator::writeStyleSheetFile(f); 09176 } 09177 cleanUpDoxygen(); 09178 exit(0); 09179 } 09180 else 09181 { 09182 err("Error: Illegal format specifier %s: should be one of rtf, html, or latex\n",formatName); 09183 cleanUpDoxygen(); 09184 exit(1); 09185 } 09186 break; 09187 case 'm': 09188 g_dumpSymbolMap = TRUE; 09189 break; 09190 case '-': 09191 if (strcmp(&argv[optind][2],"help")==0) 09192 { 09193 usage(argv[0]); 09194 } 09195 else if (strcmp(&argv[optind][2],"version")==0) 09196 { 09197 msg("%s\n",versionString); 09198 cleanUpDoxygen(); 09199 exit(0); 09200 } 09201 break; 09202 case 'b': 09203 setvbuf(stdout,NULL,_IONBF,0); 09204 Doxygen::outputToWizard=TRUE; 09205 break; 09206 case 'h': 09207 case '?': 09208 usage(argv[0]); 09209 break; 09210 default: 09211 err("Unknown option -%c\n",argv[optind][1]); 09212 usage(argv[0]); 09213 } 09214 optind++; 09215 } 09216 09217 /************************************************************************** 09218 * Parse or generate the config file * 09219 **************************************************************************/ 09220 09221 Config::instance()->init(); 09222 09223 if (genConfig) 09224 { 09225 generateConfigFile(configName,shortList); 09226 cleanUpDoxygen(); 09227 exit(0); 09228 } 09229 09230 QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile"); 09231 if (optind>=argc) 09232 { 09233 if (configFileInfo1.exists()) 09234 { 09235 configName="Doxyfile"; 09236 } 09237 else if (configFileInfo2.exists()) 09238 { 09239 configName="doxyfile"; 09240 } 09241 else 09242 { 09243 err("Doxyfile not found and no input file specified!\n"); 09244 usage(argv[0]); 09245 } 09246 } 09247 else 09248 { 09249 QFileInfo fi(argv[optind]); 09250 if (fi.exists() || strcmp(argv[optind],"-")==0) 09251 { 09252 configName=argv[optind]; 09253 } 09254 else 09255 { 09256 err("Error: configuration file %s not found!\n",argv[optind]); 09257 usage(argv[0]); 09258 } 09259 } 09260 09261 09262 if (!Config::instance()->parse(configName)) 09263 { 09264 err("Error: could not open or read configuration file %s!\n",configName); 09265 cleanUpDoxygen(); 09266 exit(1); 09267 } 09268 09269 if (updateConfig) 09270 { 09271 generateConfigFile(configName,shortList,TRUE); 09272 cleanUpDoxygen(); 09273 exit(0); 09274 } 09275 09276 /* Perlmod wants to know the path to the config file.*/ 09277 QFileInfo configFileInfo(configName); 09278 setPerlModDoxyfile(configFileInfo.absFilePath()); 09279 } 09280 09281 void checkConfiguration() 09282 { 09283 09284 Config::instance()->substituteEnvironmentVars(); 09285 Config::instance()->convertStrToVal(); 09286 Config::instance()->check(); 09287 09288 initWarningFormat(); 09289 09290 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); 09291 if (!setTranslator(outputLanguage)) 09292 { 09293 err("Warning: Output language %s not supported! Using English instead.\n", 09294 outputLanguage.data()); 09295 } 09296 QStrList &includePath = Config_getList("INCLUDE_PATH"); 09297 char *s=includePath.first(); 09298 while (s) 09299 { 09300 QFileInfo fi(s); 09301 addSearchDir(fi.absFilePath()); 09302 s=includePath.next(); 09303 } 09304 09305 /* Set the global html file extension. */ 09306 Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION"); 09307 09308 09309 Doxygen::xrefLists->setAutoDelete(TRUE); 09310 09311 Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || 09312 Config_getBool("CALLER_GRAPH") || 09313 Config_getBool("REFERENCES_RELATION") || 09314 Config_getBool("REFERENCED_BY_RELATION"); 09315 09316 09317 } 09318 09319 #ifdef HAS_SIGNALS 09320 static void stopDoxygen(int) 09321 { 09322 QDir thisDir; 09323 msg("Cleaning up...\n"); 09324 if (!Doxygen::entryDBFileName.isEmpty()) 09325 { 09326 thisDir.remove(Doxygen::entryDBFileName); 09327 } 09328 if (!Doxygen::objDBFileName.isEmpty()) 09329 { 09330 thisDir.remove(Doxygen::objDBFileName); 09331 } 09332 exit(1); 09333 } 09334 #endif 09335 09336 static void exitDoxygen() 09337 { 09338 if (!g_successfulRun) // premature exit 09339 { 09340 QDir thisDir; 09341 msg("Exiting...\n"); 09342 if (!Doxygen::entryDBFileName.isEmpty()) 09343 { 09344 thisDir.remove(Doxygen::entryDBFileName); 09345 } 09346 if (!Doxygen::objDBFileName.isEmpty()) 09347 { 09348 thisDir.remove(Doxygen::objDBFileName); 09349 } 09350 } 09351 } 09352 09353 void parseInput() 09354 { 09355 atexit(exitDoxygen); 09356 09357 /************************************************************************** 09358 * Make sure the output directory exists 09359 **************************************************************************/ 09360 QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY"); 09361 if (outputDirectory.isEmpty()) 09362 { 09363 outputDirectory=QDir::currentDirPath(); 09364 } 09365 else 09366 { 09367 QDir dir(outputDirectory); 09368 if (!dir.exists()) 09369 { 09370 dir.setPath(QDir::currentDirPath()); 09371 if (!dir.mkdir(outputDirectory)) 09372 { 09373 err("Error: tag OUTPUT_DIRECTORY: Output directory `%s' does not " 09374 "exist and cannot be created\n",outputDirectory.data()); 09375 cleanUpDoxygen(); 09376 exit(1); 09377 } 09378 else if (!Config_getBool("QUIET")) 09379 { 09380 err("Notice: Output directory `%s' does not exist. " 09381 "I have created it for you.\n", outputDirectory.data()); 09382 } 09383 dir.cd(outputDirectory); 09384 } 09385 outputDirectory=dir.absPath(); 09386 } 09387 09388 /************************************************************************** 09389 * Initialize global lists and dictionaries 09390 **************************************************************************/ 09391 09392 Doxygen::symbolMap = new QDict<DefinitionIntf>(1000); 09393 Doxygen::symbolCache = new ObjCache(16); // 16 -> room for 65536 elements, 09394 // ~2.0 MByte "overhead" 09395 Doxygen::symbolStorage = new Store; 09396 09397 #ifdef HAS_SIGNALS 09398 signal(SIGINT, stopDoxygen); 09399 #endif 09400 09401 uint pid = portable_pid(); 09402 Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid); 09403 Doxygen::objDBFileName.prepend(outputDirectory+"/"); 09404 Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid); 09405 Doxygen::entryDBFileName.prepend(outputDirectory+"/"); 09406 09407 if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1) 09408 { 09409 err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data()); 09410 exit(1); 09411 } 09412 09413 Doxygen::inputNameList = new FileNameList; 09414 Doxygen::inputNameList->setAutoDelete(TRUE); 09415 Doxygen::memberNameSDict = new MemberNameSDict(10000); 09416 Doxygen::memberNameSDict->setAutoDelete(TRUE); 09417 Doxygen::functionNameSDict = new MemberNameSDict(10000); 09418 Doxygen::functionNameSDict->setAutoDelete(TRUE); 09419 Doxygen::groupSDict = new GroupSDict(17); 09420 Doxygen::groupSDict->setAutoDelete(TRUE); 09421 Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>"); 09422 Doxygen::namespaceSDict = new NamespaceSDict(20); 09423 Doxygen::namespaceSDict->setAutoDelete(TRUE); 09424 Doxygen::classSDict = new ClassSDict(1009); 09425 Doxygen::classSDict->setAutoDelete(TRUE); 09426 Doxygen::hiddenClasses = new ClassSDict(257); 09427 Doxygen::hiddenClasses->setAutoDelete(TRUE); 09428 Doxygen::directories = new DirSDict(17); 09429 Doxygen::directories->setAutoDelete(TRUE); 09430 Doxygen::pageSDict = new PageSDict(1009); // all doc pages 09431 Doxygen::pageSDict->setAutoDelete(TRUE); 09432 Doxygen::exampleSDict = new PageSDict(1009); // all examples 09433 Doxygen::exampleSDict->setAutoDelete(TRUE); 09434 Doxygen::inputNameDict = new FileNameDict(10007); 09435 Doxygen::includeNameDict = new FileNameDict(10007); 09436 Doxygen::exampleNameDict = new FileNameDict(1009); 09437 Doxygen::exampleNameDict->setAutoDelete(TRUE); 09438 Doxygen::imageNameDict = new FileNameDict(257); 09439 Doxygen::dotFileNameDict = new FileNameDict(257); 09440 Doxygen::sectionDict.setAutoDelete(TRUE); 09441 Doxygen::memGrpInfoDict.setAutoDelete(TRUE); 09442 Doxygen::tagDestinationDict.setAutoDelete(TRUE); 09443 Doxygen::lookupCache.setAutoDelete(TRUE); 09444 Doxygen::dirRelations.setAutoDelete(TRUE); 09445 excludeNameDict.setAutoDelete(TRUE); 09446 09447 /************************************************************************** 09448 * Initialize some global constants 09449 **************************************************************************/ 09450 09451 int &tabSize = Config_getInt("TAB_SIZE"); 09452 spaces.resize(tabSize+1); 09453 int sp;for (sp=0;sp<tabSize;sp++) spaces.at(sp)=' '; 09454 spaces.at(tabSize)='\0'; 09455 09456 compoundKeywordDict.insert("template class",(void *)8); 09457 compoundKeywordDict.insert("template struct",(void *)8); 09458 compoundKeywordDict.insert("class",(void *)8); 09459 compoundKeywordDict.insert("struct",(void *)8); 09460 compoundKeywordDict.insert("union",(void *)8); 09461 compoundKeywordDict.insert("interface",(void *)8); 09462 compoundKeywordDict.insert("exception",(void *)8); 09463 09464 bool alwaysRecursive = Config_getBool("RECURSIVE"); 09465 09466 /************************************************************************** 09467 * Check/create output directorties * 09468 **************************************************************************/ 09469 09470 QCString &htmlOutput = Config_getString("HTML_OUTPUT"); 09471 bool &generateHtml = Config_getBool("GENERATE_HTML"); 09472 if (htmlOutput.isEmpty() && generateHtml) 09473 { 09474 htmlOutput=outputDirectory+"/html"; 09475 } 09476 else if (htmlOutput && htmlOutput[0]!='/' && htmlOutput[1]!=':') 09477 { 09478 htmlOutput.prepend(outputDirectory+'/'); 09479 } 09480 QDir htmlDir(htmlOutput); 09481 if (generateHtml && !htmlDir.exists() && !htmlDir.mkdir(htmlOutput)) 09482 { 09483 err("Could not create output directory %s\n",htmlOutput.data()); 09484 cleanUpDoxygen(); 09485 exit(1); 09486 } 09487 09488 QCString &xmlOutput = Config_getString("XML_OUTPUT"); 09489 bool &generateXml = Config_getBool("GENERATE_XML"); 09490 if (xmlOutput.isEmpty() && generateXml) 09491 { 09492 xmlOutput=outputDirectory+"/xml"; 09493 } 09494 else if (xmlOutput && xmlOutput[0]!='/' && xmlOutput[1]!=':') 09495 { 09496 xmlOutput.prepend(outputDirectory+'/'); 09497 } 09498 QDir xmlDir(xmlOutput); 09499 if (generateXml && !xmlDir.exists() && !xmlDir.mkdir(xmlOutput)) 09500 { 09501 err("Could not create output directory %s\n",xmlOutput.data()); 09502 cleanUpDoxygen(); 09503 exit(1); 09504 } 09505 09506 QCString &latexOutput = Config_getString("LATEX_OUTPUT"); 09507 bool &generateLatex = Config_getBool("GENERATE_LATEX"); 09508 if (latexOutput.isEmpty() && generateLatex) 09509 { 09510 latexOutput=outputDirectory+"/latex"; 09511 } 09512 else if (latexOutput && latexOutput[0]!='/' && latexOutput[1]!=':') 09513 { 09514 latexOutput.prepend(outputDirectory+'/'); 09515 } 09516 QDir latexDir(latexOutput); 09517 if (generateLatex && !latexDir.exists() && !latexDir.mkdir(latexOutput)) 09518 { 09519 err("Could not create output directory %s\n",latexOutput.data()); 09520 cleanUpDoxygen(); 09521 exit(1); 09522 } 09523 09524 QCString &rtfOutput = Config_getString("RTF_OUTPUT"); 09525 bool &generateRtf = Config_getBool("GENERATE_RTF"); 09526 if (rtfOutput.isEmpty() && generateRtf) 09527 { 09528 rtfOutput=outputDirectory+"/rtf"; 09529 } 09530 else if (rtfOutput && rtfOutput[0]!='/' && rtfOutput[1]!=':') 09531 { 09532 rtfOutput.prepend(outputDirectory+'/'); 09533 } 09534 QDir rtfDir(rtfOutput); 09535 if (generateRtf && !rtfDir.exists() && !rtfDir.mkdir(rtfOutput)) 09536 { 09537 err("Could not create output directory %s\n",rtfOutput.data()); 09538 cleanUpDoxygen(); 09539 exit(1); 09540 } 09541 09542 QCString &manOutput = Config_getString("MAN_OUTPUT"); 09543 bool &generateMan = Config_getBool("GENERATE_MAN"); 09544 if (manOutput.isEmpty() && generateMan) 09545 { 09546 manOutput=outputDirectory+"/man"; 09547 } 09548 else if (manOutput && manOutput[0]!='/' && manOutput[1]!=':') 09549 { 09550 manOutput.prepend(outputDirectory+'/'); 09551 } 09552 QDir manDir(manOutput); 09553 if (generateMan && !manDir.exists() && !manDir.mkdir(manOutput)) 09554 { 09555 err("Could not create output directory %s\n",manOutput.data()); 09556 cleanUpDoxygen(); 09557 exit(1); 09558 } 09559 /************************************************************************** 09560 * Read and preprocess input * 09561 **************************************************************************/ 09562 09563 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS"); 09564 // prevent search in the output directories 09565 if (generateHtml) exclPatterns.append(htmlOutput); 09566 if (generateXml) exclPatterns.append(xmlOutput); 09567 if (generateLatex) exclPatterns.append(latexOutput); 09568 if (generateRtf) exclPatterns.append(rtfOutput); 09569 if (generateMan) exclPatterns.append(manOutput); 09570 09571 // gather names of all files in the include path 09572 msg("Searching for include files...\n"); 09573 QStrList &includePathList = Config_getList("INCLUDE_PATH"); 09574 char *s=includePathList.first(); 09575 while (s) 09576 { 09577 QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS"); 09578 if (pl.count()==0) 09579 { 09580 pl = Config_getList("FILE_PATTERNS"); 09581 } 09582 readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl, 09583 &exclPatterns,0,0, 09584 alwaysRecursive); 09585 s=includePathList.next(); 09586 } 09587 09588 msg("Searching for example files...\n"); 09589 QStrList &examplePathList = Config_getList("EXAMPLE_PATH"); 09590 s=examplePathList.first(); 09591 while (s) 09592 { 09593 readFileOrDirectory(s,0,Doxygen::exampleNameDict,0, 09594 &Config_getList("EXAMPLE_PATTERNS"), 09595 0,0,0, 09596 (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE"))); 09597 s=examplePathList.next(); 09598 } 09599 09600 msg("Searching for images...\n"); 09601 QStrList &imagePathList=Config_getList("IMAGE_PATH"); 09602 s=imagePathList.first(); 09603 while (s) 09604 { 09605 readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0, 09606 0,0,0, 09607 alwaysRecursive); 09608 s=imagePathList.next(); 09609 } 09610 09611 msg("Searching for dot files...\n"); 09612 QStrList &dotFileList=Config_getList("DOTFILE_DIRS"); 09613 s=dotFileList.first(); 09614 while (s) 09615 { 09616 readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0, 09617 0,0,0, 09618 alwaysRecursive); 09619 s=dotFileList.next(); 09620 } 09621 09622 msg("Searching for files to exclude\n"); 09623 QStrList &excludeList = Config_getList("EXCLUDE"); 09624 s=excludeList.first(); 09625 while (s) 09626 { 09627 readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"), 09628 0,0,&excludeNameDict, 09629 alwaysRecursive, 09630 FALSE); 09631 s=excludeList.next(); 09632 } 09633 09634 /************************************************************************** 09635 * Determine Input Files * 09636 **************************************************************************/ 09637 09638 msg("Searching for files to process...\n"); 09639 QDict<void> *killDict = new QDict<void>(10007); 09640 int inputSize=0; 09641 QStrList &inputList=Config_getList("INPUT"); 09642 inputFiles.setAutoDelete(TRUE); 09643 s=inputList.first(); 09644 while (s) 09645 { 09646 QCString path=s; 09647 uint l = path.length(); 09648 // strip trailing slashes 09649 if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1); 09650 09651 inputSize+=readFileOrDirectory( 09652 path, 09653 Doxygen::inputNameList, 09654 Doxygen::inputNameDict, 09655 &excludeNameDict, 09656 &Config_getList("FILE_PATTERNS"), 09657 &exclPatterns, 09658 &inputFiles,0, 09659 alwaysRecursive, 09660 TRUE, 09661 killDict); 09662 s=inputList.next(); 09663 } 09664 delete killDict; 09665 09666 // add predefined macro name to a dictionary 09667 QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED"); 09668 s=expandAsDefinedList.first(); 09669 while (s) 09670 { 09671 if (Doxygen::expandAsDefinedDict[s]==0) 09672 { 09673 Doxygen::expandAsDefinedDict.insert(s,(void *)666); 09674 } 09675 s=expandAsDefinedList.next(); 09676 } 09677 09678 // read aliases and store them in a dictionary 09679 readAliases(); 09680 09681 09682 // Notice: the order of the function calls below is very important! 09683 09684 if (Config_getBool("GENERATE_HTML")) 09685 { 09686 readFormulaRepository(); 09687 } 09688 09689 /************************************************************************** 09690 * Handle Tag Files * 09691 **************************************************************************/ 09692 09693 g_storage = new FileStorage; 09694 g_storage->setName(Doxygen::entryDBFileName); 09695 if (!g_storage->open(IO_WriteOnly)) 09696 { 09697 err("Failed to create temporary storage file %s\n", 09698 Doxygen::entryDBFileName.data()); 09699 exit(1); 09700 } 09701 Entry *root=new Entry; 09702 EntryNav *rootNav = new EntryNav(0,root); 09703 rootNav->setEntry(root); 09704 msg("Reading and parsing tag files\n"); 09705 09706 QStrList &tagFileList = Config_getList("TAGFILES"); 09707 s=tagFileList.first(); 09708 while (s) 09709 { 09710 readTagFile(root,s); 09711 root->createNavigationIndex(rootNav,g_storage,0); 09712 s=tagFileList.next(); 09713 } 09714 09715 /************************************************************************** 09716 * Parse source files * 09717 **************************************************************************/ 09718 09719 parseFiles(root,rootNav); 09720 g_storage->close(); 09721 if (!g_storage->open(IO_ReadOnly)) 09722 { 09723 err("Failed to open temporary storage file %s for reading", 09724 Doxygen::entryDBFileName.data()); 09725 exit(1); 09726 } 09727 09728 //printNavTree(rootNav,0); 09729 09730 // we are done with input scanning now, so free up the buffers used by flex 09731 // (can be around 4MB) 09732 preFreeScanner(); 09733 scanFreeScanner(); 09734 pyscanFreeScanner(); 09735 09736 //delete rootNav; 09737 //g_storage.close(); 09738 //exit(1); 09739 09740 /************************************************************************** 09741 * Gather information * 09742 **************************************************************************/ 09743 09744 msg("Building group list...\n"); 09745 buildGroupList(rootNav); 09746 organizeSubGroups(rootNav); 09747 09748 msg("Building directory list...\n"); 09749 buildDirectories(); 09750 findDirDocumentation(rootNav); 09751 09752 if (Config_getBool("BUILTIN_STL_SUPPORT")) 09753 { 09754 addSTLClasses(rootNav); 09755 } 09756 09757 msg("Building namespace list...\n"); 09758 buildNamespaceList(rootNav); 09759 findUsingDirectives(rootNav); 09760 09761 msg("Building file list...\n"); 09762 buildFileList(rootNav); 09763 //generateFileTree(); 09764 09765 msg("Searching for included using directives...\n"); 09766 findIncludedUsingDirectives(); 09767 09768 msg("Building class list...\n"); 09769 buildClassList(rootNav); 09770 09771 msg("Associating documentation with classes...\n"); 09772 buildClassDocList(rootNav); 09773 09774 // build list of using declarations here (global list) 09775 buildListOfUsingDecls(rootNav); 09776 09777 msg("Computing nesting relations for classes...\n"); 09778 resolveClassNestingRelations(); 09779 09780 // calling buildClassList may result in cached relations that 09781 // become invalid after resolveClassNestingRelation(), that's why 09782 // we need to clear the cache here 09783 Doxygen::lookupCache.clear(); 09784 // we don't need the list of using declaration anymore 09785 g_usingDeclarations.clear(); 09786 09787 msg("Searching for members imported via using declarations...\n"); 09788 findUsingDeclImports(rootNav); 09789 findUsingDeclarations(rootNav); 09790 09791 msg("Building example list...\n"); 09792 buildExampleList(rootNav); 09793 09794 msg("Searching for enumerations...\n"); 09795 findEnums(rootNav); 09796 09797 msg("Searching for documented variables...\n"); 09798 buildVarList(rootNav); 09799 09800 msg("Building member list...\n"); // using class info only ! 09801 buildFunctionList(rootNav); 09802 09803 msg("Searching for friends...\n"); 09804 findFriends(); 09805 09806 msg("Searching for documented defines...\n"); 09807 findDefineDocumentation(rootNav); 09808 09809 findClassEntries(rootNav); 09810 msg("Computing class inheritance relations...\n"); 09811 findInheritedTemplateInstances(); 09812 msg("Computing class usage relations...\n"); 09813 findUsedTemplateInstances(); 09814 09815 msg("Flushing cached template relations that have become invalid...\n"); 09816 flushCachedTemplateRelations(); 09817 09818 msg("Creating members for template instances...\n"); 09819 createTemplateInstanceMembers(); 09820 09821 msg("Computing class relations...\n"); 09822 computeTemplateClassRelations(); 09823 flushUnresolvedRelations(); 09824 //if (Config_getBool("OPTIMIZE_OUTPUT_VHDL")) 09825 //{ 09826 // VhdlDocGen::computeVhdlComponentRelations(classEntries,g_storage); 09827 //} 09828 //else 09829 //{ 09830 computeClassRelations(); 09831 //} 09832 classEntries.clear(); 09833 09834 addEnumValuesToEnums(rootNav); 09835 findEnumDocumentation(rootNav); 09836 09837 msg("Searching for member function documentation...\n"); 09838 findObjCMethodDefinitions(rootNav); 09839 findMemberDocumentation(rootNav); // may introduce new members ! 09840 09841 transferRelatedFunctionDocumentation(); 09842 transferFunctionDocumentation(); 09843 09844 msg("Building page list...\n"); 09845 buildPageList(rootNav); 09846 09847 msg("Search for main page...\n"); 09848 findMainPage(rootNav); 09849 09850 msg("Computing page relations...\n"); 09851 computePageRelations(rootNav); 09852 checkPageRelations(); 09853 09854 msg("Determining the scope of groups...\n"); 09855 findGroupScope(rootNav); 09856 09857 msg("Sorting lists...\n"); 09858 Doxygen::memberNameSDict->sort(); 09859 Doxygen::functionNameSDict->sort(); 09860 Doxygen::hiddenClasses->sort(); 09861 Doxygen::classSDict->sort(); 09862 09863 msg("Freeing entry tree\n"); 09864 delete rootNav; 09865 g_storage->close(); 09866 delete g_storage; 09867 g_storage=0; 09868 09869 QDir thisDir; 09870 thisDir.remove(Doxygen::entryDBFileName); 09871 09872 msg("Determining which enums are documented\n"); 09873 findDocumentedEnumValues(); 09874 09875 msg("Computing member relations...\n"); 09876 computeMemberRelations(); 09877 09878 msg("Building full member lists recursively...\n"); 09879 buildCompleteMemberLists(); 09880 09881 msg("Adding members to member groups.\n"); 09882 addMembersToMemberGroup(); 09883 09884 if (Config_getBool("DISTRIBUTE_GROUP_DOC")) 09885 { 09886 msg("Distributing member group documentation.\n"); 09887 distributeMemberGroupDocumentation(); 09888 } 09889 09890 msg("Computing member references...\n"); 09891 computeMemberReferences(); 09892 09893 if (Config_getBool("INHERIT_DOCS")) 09894 { 09895 msg("Inheriting documentation...\n"); 09896 inheritDocumentation(); 09897 } 09898 09899 // compute the shortest possible names of all files 09900 // without loosing the uniqueness of the file names. 09901 msg("Generating disk names...\n"); 09902 Doxygen::inputNameList->generateDiskNames(); 09903 09904 msg("Adding source references...\n"); 09905 addSourceReferences(); 09906 09907 msg("Adding todo/test/bug list items...\n"); 09908 addListReferences(); 09909 09910 if (Config_getBool("SHOW_DIRECTORIES") && Config_getBool("DIRECTORY_GRAPH")) 09911 { 09912 msg("Computing dependencies between directories...\n"); 09913 computeDirDependencies(); 09914 } 09915 09916 msg("Counting data structures...\n"); 09917 countDataStructures(); 09918 09919 msg("Resolving user defined references...\n"); 09920 resolveUserReferences(); 09921 09922 msg("Finding anchors and sections in the documentation...\n"); 09923 findSectionsInDocumentation(); 09924 09925 transferFunctionReferences(); 09926 09927 msg("Combining using relations...\n"); 09928 combineUsingRelations(); 09929 09930 } 09931 09932 void generateOutput() 09933 { 09934 /************************************************************************** 09935 * Initialize output generators * 09936 **************************************************************************/ 09937 09939 //SDict<DefinitionList>::Iterator sdi(Doxygen::symbolMap); 09940 //DefinitionList *dl; 09941 //for (sdi.toFirst();(dl=sdi.current());++sdi) 09942 //{ 09943 // DefinitionListIterator dli(*dl); 09944 // Definition *d; 09945 // printf("Symbol: "); 09946 // for (dli.toFirst();(d=dli.current());++dli) 09947 // { 09948 // printf("%s ",d->qualifiedName().data()); 09949 // } 09950 // printf("\n"); 09951 //} 09952 if (g_dumpSymbolMap) 09953 { 09954 dumpSymbolMap(); 09955 exit(0); 09956 } 09957 09958 initDocParser(); 09959 09960 outputList = new OutputList(TRUE); 09961 if (Config_getBool("GENERATE_HTML")) 09962 { 09963 outputList->add(new HtmlGenerator); 09964 HtmlGenerator::init(); 09965 if (Config_getBool("GENERATE_HTMLHELP")) Doxygen::indexList.addIndex(new HtmlHelp); 09966 if (Config_getBool("GENERATE_TREEVIEW")) Doxygen::indexList.addIndex(new FTVHelp); 09967 if (Config_getBool("GENERATE_DOCSET")) Doxygen::indexList.addIndex(new DocSets); 09968 Doxygen::indexList.initialize(); 09969 if (Config_getBool("HTML_DYNAMIC_SECTIONS")) HtmlGenerator::generateSectionImages(); 09970 copyStyleSheet(); 09971 } 09972 if (Config_getBool("GENERATE_LATEX")) 09973 { 09974 outputList->add(new LatexGenerator); 09975 LatexGenerator::init(); 09976 } 09977 if (Config_getBool("GENERATE_MAN")) 09978 { 09979 outputList->add(new ManGenerator); 09980 ManGenerator::init(); 09981 } 09982 if (Config_getBool("GENERATE_RTF")) 09983 { 09984 outputList->add(new RTFGenerator); 09985 RTFGenerator::init(); 09986 } 09987 09988 if (Config_getBool("USE_HTAGS")) 09989 { 09990 Htags::useHtags = TRUE; 09991 QCString htmldir = Config_getString("HTML_OUTPUT"); 09992 if (!Htags::execute(htmldir)) 09993 err("Error: USE_HTAGS is YES but htags(1) failed. \n"); 09994 if (!Htags::loadFilemap(htmldir)) 09995 err("Error: htags(1) ended normally but failed to load the filemap. \n"); 09996 } 09997 09998 /************************************************************************** 09999 * Generate documentation * 10000 **************************************************************************/ 10001 10002 QFile *tag=0; 10003 QCString &generateTagFile = Config_getString("GENERATE_TAGFILE"); 10004 if (!generateTagFile.isEmpty()) 10005 { 10006 tag=new QFile(generateTagFile); 10007 if (!tag->open(IO_WriteOnly)) 10008 { 10009 err("Error: cannot open tag file %s for writing\n", 10010 generateTagFile.data() 10011 ); 10012 cleanUpDoxygen(); 10013 exit(1); 10014 } 10015 Doxygen::tagFile.setDevice(tag); 10016 Doxygen::tagFile.setEncoding(QTextStream::UnicodeUTF8); 10017 Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?>" << endl; 10018 Doxygen::tagFile << "<tagfile>" << endl; 10019 } 10020 10021 if (Config_getBool("GENERATE_HTML")) writeDoxFont(Config_getString("HTML_OUTPUT")); 10022 if (Config_getBool("GENERATE_LATEX")) writeDoxFont(Config_getString("LATEX_OUTPUT")); 10023 if (Config_getBool("GENERATE_RTF")) writeDoxFont(Config_getString("RTF_OUTPUT")); 10024 10025 msg("Generating style sheet...\n"); 10026 //printf("writing style info\n"); 10027 QCString genString = 10028 theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME")); 10029 outputList->writeStyleInfo(0); // write first part 10030 outputList->disableAllBut(OutputGenerator::Latex); 10031 outputList->parseText(genString); 10032 outputList->writeStyleInfo(1); // write second part 10033 //parseText(*outputList,theTranslator->trWrittenBy()); 10034 outputList->writeStyleInfo(2); // write third part 10035 outputList->parseText(genString); 10036 outputList->writeStyleInfo(3); // write fourth part 10037 //parseText(*outputList,theTranslator->trWrittenBy()); 10038 outputList->writeStyleInfo(4); // write last part 10039 outputList->enableAll(); 10040 10041 //statistics(); 10042 10043 // count the number of documented elements in the lists we have built. 10044 // If the result is 0 we do not generate the lists and omit the 10045 // corresponding links in the index. 10046 msg("Generating index page...\n"); 10047 writeIndex(*outputList); 10048 10049 msg("Generating page index...\n"); 10050 writePageIndex(*outputList); 10051 10052 msg("Generating example documentation...\n"); 10053 generateExampleDocs(); 10054 10055 msg("Generating file sources...\n"); 10056 if (!Htags::useHtags) 10057 { 10058 generateFileSources(); 10059 } 10060 10061 msg("Generating file documentation...\n"); 10062 generateFileDocs(); 10063 10064 msg("Generating page documentation...\n"); 10065 generatePageDocs(); 10066 10067 msg("Generating group documentation...\n"); 10068 generateGroupDocs(); 10069 10070 msg("Generating group index...\n"); 10071 writeGroupIndex(*outputList); 10072 10073 msg("Generating class documentation...\n"); 10074 addMembersToIndex(); 10075 generateClassDocs(); 10076 10077 if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY")) 10078 { 10079 msg("Generating graphical class hierarchy...\n"); 10080 writeGraphicalClassHierarchy(*outputList); 10081 } 10082 10083 msg("Generating namespace index...\n"); 10084 generateNamespaceDocs(); 10085 10086 msg("Generating namespace member index...\n"); 10087 writeNamespaceMemberIndex(*outputList); 10088 10089 if (Config_getBool("GENERATE_LEGEND")) 10090 { 10091 msg("Generating graph info page...\n"); 10092 writeGraphInfo(*outputList); 10093 } 10094 10095 if (Config_getBool("SHOW_DIRECTORIES")) 10096 { 10097 msg("Generating directory documentation...\n"); 10098 generateDirDocs(*outputList); 10099 } 10100 10101 msg("Generating file index...\n"); 10102 writeFileIndex(*outputList); 10103 10104 if (Config_getBool("SHOW_DIRECTORIES")) 10105 { 10106 msg("Generating directory index...\n"); 10107 writeDirIndex(*outputList); 10108 } 10109 10110 msg("Generating example index...\n"); 10111 writeExampleIndex(*outputList); 10112 10113 msg("Generating file member index...\n"); 10114 writeFileMemberIndex(*outputList); 10115 10116 //writeDirDependencyGraph(Config_getString("HTML_OUTPUT")); 10117 10118 if (Config_getBool("GENERATE_RTF")) 10119 { 10120 msg("Combining RTF output...\n"); 10121 if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf")) 10122 { 10123 err("An error occurred during post-processing the RTF files!\n"); 10124 } 10125 } 10126 10127 if (Doxygen::formulaList.count()>0 && Config_getBool("GENERATE_HTML")) 10128 { 10129 msg("Generating bitmaps for formulas in HTML...\n"); 10130 Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT")); 10131 } 10132 10133 //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_HTMLHELP")) 10134 //{ 10135 // HtmlHelp::getInstance()->finalize(); 10136 //} 10137 //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_TREEVIEW")) 10138 //{ 10139 // FTVHelp::getInstance()->finalize(); 10140 //} 10141 10142 Doxygen::indexList.finalize(); 10143 10144 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 10145 { 10146 Doxygen::tagFile << "</tagfile>" << endl; 10147 delete tag; 10148 } 10149 10150 if (Config_getBool("GENERATE_HTML") && Config_getBool("DOT_CLEANUP")) removeDoxFont(Config_getString("HTML_OUTPUT")); 10151 if (Config_getBool("GENERATE_RTF") && Config_getBool("DOT_CLEANUP")) removeDoxFont(Config_getString("RTF_OUTPUT")); 10152 10153 if (Config_getBool("GENERATE_XML")) 10154 { 10155 msg("Generating XML output...\n"); 10156 generateXML(); 10157 } 10158 if (Config_getBool("GENERATE_AUTOGEN_DEF")) 10159 { 10160 msg("Generating AutoGen DEF output...\n"); 10161 generateDEF(); 10162 } 10163 if (Config_getBool("GENERATE_PERLMOD")) 10164 { 10165 msg("Generating Perl module output...\n"); 10166 generatePerlMod(); 10167 } 10168 if (Config_getBool("GENERATE_HTMLHELP") && !Config_getString("HHC_LOCATION").isEmpty()) 10169 { 10170 msg("Running html help compiler...\n"); 10171 QString oldDir = QDir::currentDirPath(); 10172 QDir::setCurrent(Config_getString("HTML_OUTPUT")); 10173 if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE)) 10174 { 10175 err("Error: failed to run html help compiler on index.hhp\n"); 10176 } 10177 QDir::setCurrent(oldDir); 10178 } 10179 if (Config_getBool("SEARCHENGINE")) 10180 { 10181 msg("Generating search index\n"); 10182 HtmlGenerator::writeSearchPage(); 10183 Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search.idx"); 10184 } 10185 if (Debug::isFlagSet(Debug::Time)) 10186 { 10187 msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n", 10188 ((double)Doxygen::runningTime.elapsed())/1000.0, 10189 Doxygen::sysElapsedTime 10190 ); 10191 } 10192 10193 /************************************************************************** 10194 * Start cleaning up * 10195 **************************************************************************/ 10196 10197 //Doxygen::symbolCache->printStats(); 10198 //Doxygen::symbolStorage->printStats(); 10199 cleanUpDoxygen(); 10200 10201 finializeDocParser(); 10202 Doxygen::symbolStorage->close(); 10203 QDir thisDir; 10204 thisDir.remove(Doxygen::objDBFileName); 10205 Config::deleteInstance(); 10206 QTextCodec::deleteAllCodecs(); 10207 delete Doxygen::symbolCache; 10208 delete Doxygen::symbolMap; 10209 delete Doxygen::symbolStorage; 10210 g_successfulRun=TRUE; 10211 } 10212