|
1 /****************************************************************************** |
|
2 * |
|
3 * Copyright (C) 1997-2008 by Dimitri van Heesch. |
|
4 * |
|
5 * Permission to use, copy, modify, and distribute this software and its |
|
6 * documentation under the terms of the GNU General Public License is hereby |
|
7 * granted. No representations are made about the suitability of this software |
|
8 * for any purpose. It is provided "as is" without express or implied warranty. |
|
9 * See the GNU General Public License for more details. |
|
10 * |
|
11 * Documents produced by Doxygen are derivative works derived from the |
|
12 * input used in their production; they are not affected by this license. |
|
13 * |
|
14 */ |
|
15 |
|
16 #include "qtbc.h" |
|
17 #include <qfileinfo.h> |
|
18 #include <qfile.h> |
|
19 #include <qdir.h> |
|
20 #include <qdict.h> |
|
21 #include <qregexp.h> |
|
22 #include <qstrlist.h> |
|
23 #include <stdio.h> |
|
24 #include <stdlib.h> |
|
25 #include <sys/stat.h> |
|
26 #include <qtextcodec.h> |
|
27 #include <unistd.h> |
|
28 #include <errno.h> |
|
29 |
|
30 #include "version.h" |
|
31 #include "doxygen.h" |
|
32 #include "scanner.h" |
|
33 #include "entry.h" |
|
34 #include "index.h" |
|
35 #include "logos.h" |
|
36 #include "instdox.h" |
|
37 #include "message.h" |
|
38 #include "config.h" |
|
39 #include "util.h" |
|
40 #include "pre.h" |
|
41 #include "tagreader.h" |
|
42 #include "dot.h" |
|
43 #include "docparser.h" |
|
44 #include "dirdef.h" |
|
45 #include "outputlist.h" |
|
46 #include "declinfo.h" |
|
47 #include "htmlgen.h" |
|
48 #include "latexgen.h" |
|
49 #include "mangen.h" |
|
50 #include "language.h" |
|
51 #include "debug.h" |
|
52 #include "htmlhelp.h" |
|
53 #include "qhp.h" |
|
54 #include "indexlog.h" |
|
55 #include "ftvhelp.h" |
|
56 #include "defargs.h" |
|
57 #include "rtfgen.h" |
|
58 #include "xmlgen.h" |
|
59 #include "xmlditagen.h" |
|
60 #include "defgen.h" |
|
61 #include "perlmodgen.h" |
|
62 #include "reflist.h" |
|
63 #include "pagedef.h" |
|
64 #include "bufstr.h" |
|
65 #include "commentcnv.h" |
|
66 #include "cmdmapper.h" |
|
67 #include "searchindex.h" |
|
68 #include "parserintf.h" |
|
69 #include "htags.h" |
|
70 #include "pyscanner.h" |
|
71 #include "fortranscanner.h" |
|
72 #include "dbusxmlscanner.h" |
|
73 #include "code.h" |
|
74 #include "objcache.h" |
|
75 #include "store.h" |
|
76 #include "marshal.h" |
|
77 #include "portable.h" |
|
78 #include "vhdlscanner.h" |
|
79 #include "vhdldocgen.h" |
|
80 #include "eclipsehelp.h" |
|
81 |
|
82 #include "layout.h" |
|
83 |
|
84 #define RECURSE_ENTRYTREE(func,var) \ |
|
85 do { if (var->children()) { \ |
|
86 EntryNavListIterator eli(*var->children()); \ |
|
87 for (;eli.current();++eli) func(eli.current()); \ |
|
88 } } while(0) |
|
89 |
|
90 |
|
91 #if !defined(_WIN32) || defined(__CYGWIN__) |
|
92 #include <signal.h> |
|
93 #define HAS_SIGNALS |
|
94 #endif |
|
95 |
|
96 // globally accessible variables |
|
97 ClassSDict *Doxygen::classSDict = 0; |
|
98 ClassSDict *Doxygen::hiddenClasses = 0; |
|
99 NamespaceSDict *Doxygen::namespaceSDict = 0; |
|
100 MemberNameSDict *Doxygen::memberNameSDict = 0; |
|
101 MemberNameSDict *Doxygen::functionNameSDict = 0; |
|
102 FileNameList *Doxygen::inputNameList = 0; // all input files |
|
103 FileNameDict *Doxygen::inputNameDict = 0; |
|
104 GroupSDict *Doxygen::groupSDict = 0; |
|
105 FormulaList Doxygen::formulaList; // all formulas |
|
106 FormulaDict Doxygen::formulaDict(1009); // all formulas |
|
107 FormulaDict Doxygen::formulaNameDict(1009); // the label name of all formulas |
|
108 PageSDict *Doxygen::pageSDict = 0; |
|
109 PageSDict *Doxygen::exampleSDict = 0; |
|
110 SectionDict Doxygen::sectionDict(257); // all page sections |
|
111 StringDict Doxygen::aliasDict(257); // aliases |
|
112 FileNameDict *Doxygen::includeNameDict = 0; // include names |
|
113 FileNameDict *Doxygen::exampleNameDict = 0; // examples |
|
114 FileNameDict *Doxygen::imageNameDict = 0; // images |
|
115 FileNameDict *Doxygen::dotFileNameDict = 0; // dot files |
|
116 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases |
|
117 StringDict Doxygen::tagDestinationDict(257); // all tag locations |
|
118 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded |
|
119 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading |
|
120 PageDef *Doxygen::mainPage = 0; |
|
121 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page? |
|
122 QTextStream Doxygen::tagFile; |
|
123 NamespaceDef *Doxygen::globalScope = 0; |
|
124 QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists |
|
125 bool Doxygen::parseSourcesNeeded = FALSE; |
|
126 QTime Doxygen::runningTime; |
|
127 SearchIndex * Doxygen::searchIndex=0; |
|
128 QDict<DefinitionIntf> *Doxygen::symbolMap; |
|
129 bool Doxygen::outputToWizard=FALSE; |
|
130 QDict<int> * Doxygen::htmlDirMap = 0; |
|
131 QCache<LookupInfo> Doxygen::lookupCache(50000,50000); |
|
132 DirSDict *Doxygen::directories; |
|
133 SDict<DirRelation> Doxygen::dirRelations(257); |
|
134 ParserManager *Doxygen::parserManager = 0; |
|
135 QCString Doxygen::htmlFileExtension; |
|
136 bool Doxygen::suppressDocWarnings = FALSE; |
|
137 ObjCache *Doxygen::symbolCache = 0; |
|
138 Store *Doxygen::symbolStorage; |
|
139 QCString Doxygen::objDBFileName; |
|
140 QCString Doxygen::entryDBFileName; |
|
141 bool Doxygen::gatherDefines = TRUE; |
|
142 IndexList Doxygen::indexList; |
|
143 int Doxygen::subpageNestingLevel = 0; |
|
144 bool Doxygen::userComments = FALSE; |
|
145 QCString Doxygen::spaces; |
|
146 |
|
147 // locally accessible globals |
|
148 static QDict<EntryNav> g_classEntries(1009); |
|
149 static StringList g_inputFiles; |
|
150 static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds |
|
151 static OutputList *g_outputList = 0; // list of output generating objects |
|
152 static QDict<FileDef> g_usingDeclarations(1009); // used classes |
|
153 static FileStorage *g_storage = 0; |
|
154 static bool g_successfulRun = FALSE; |
|
155 static bool g_dumpSymbolMap = FALSE; |
|
156 static bool g_dumpConfigAsXML = FALSE; |
|
157 |
|
158 void clearAll() |
|
159 { |
|
160 g_inputFiles.clear(); |
|
161 //g_excludeNameDict.clear(); |
|
162 //delete g_outputList; g_outputList=0; |
|
163 |
|
164 Doxygen::classSDict->clear(); |
|
165 Doxygen::namespaceSDict->clear(); |
|
166 Doxygen::pageSDict->clear(); |
|
167 Doxygen::exampleSDict->clear(); |
|
168 Doxygen::inputNameList->clear(); |
|
169 Doxygen::formulaList.clear(); |
|
170 Doxygen::sectionDict.clear(); |
|
171 Doxygen::inputNameDict->clear(); |
|
172 Doxygen::includeNameDict->clear(); |
|
173 Doxygen::exampleNameDict->clear(); |
|
174 Doxygen::imageNameDict->clear(); |
|
175 Doxygen::dotFileNameDict->clear(); |
|
176 Doxygen::formulaDict.clear(); |
|
177 Doxygen::formulaNameDict.clear(); |
|
178 Doxygen::tagDestinationDict.clear(); |
|
179 delete Doxygen::mainPage; Doxygen::mainPage=0; |
|
180 } |
|
181 |
|
182 void statistics() |
|
183 { |
|
184 fprintf(stderr,"--- inputNameDict stats ----\n"); |
|
185 Doxygen::inputNameDict->statistics(); |
|
186 fprintf(stderr,"--- includeNameDict stats ----\n"); |
|
187 Doxygen::includeNameDict->statistics(); |
|
188 fprintf(stderr,"--- exampleNameDict stats ----\n"); |
|
189 Doxygen::exampleNameDict->statistics(); |
|
190 fprintf(stderr,"--- imageNameDict stats ----\n"); |
|
191 Doxygen::imageNameDict->statistics(); |
|
192 fprintf(stderr,"--- dotFileNameDict stats ----\n"); |
|
193 Doxygen::dotFileNameDict->statistics(); |
|
194 //fprintf(stderr,"--- g_excludeNameDict stats ----\n"); |
|
195 //g_excludeNameDict.statistics(); |
|
196 fprintf(stderr,"--- aliasDict stats ----\n"); |
|
197 Doxygen::aliasDict.statistics(); |
|
198 fprintf(stderr,"--- typedefDict stats ----\n"); |
|
199 fprintf(stderr,"--- namespaceAliasDict stats ----\n"); |
|
200 Doxygen::namespaceAliasDict.statistics(); |
|
201 fprintf(stderr,"--- formulaDict stats ----\n"); |
|
202 Doxygen::formulaDict.statistics(); |
|
203 fprintf(stderr,"--- formulaNameDict stats ----\n"); |
|
204 Doxygen::formulaNameDict.statistics(); |
|
205 fprintf(stderr,"--- tagDestinationDict stats ----\n"); |
|
206 Doxygen::tagDestinationDict.statistics(); |
|
207 fprintf(stderr,"--- g_compoundKeywordDict stats ----\n"); |
|
208 g_compoundKeywordDict.statistics(); |
|
209 fprintf(stderr,"--- expandAsDefinedDict stats ----\n"); |
|
210 Doxygen::expandAsDefinedDict.statistics(); |
|
211 fprintf(stderr,"--- memGrpInfoDict stats ----\n"); |
|
212 Doxygen::memGrpInfoDict.statistics(); |
|
213 } |
|
214 |
|
215 |
|
216 |
|
217 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl, |
|
218 ArgumentList *al,bool over_load,NamespaceSDict *nl=0); |
|
219 static void findMember(EntryNav *rootNav, |
|
220 QCString funcDecl, |
|
221 bool overloaded, |
|
222 bool isFunc |
|
223 ); |
|
224 |
|
225 |
|
226 struct STLInfo |
|
227 { |
|
228 const char *className; |
|
229 const char *baseClass1; |
|
230 const char *baseClass2; |
|
231 const char *templType1; |
|
232 const char *templName1; |
|
233 const char *templType2; |
|
234 const char *templName2; |
|
235 bool virtualInheritance; |
|
236 bool iterators; |
|
237 }; |
|
238 |
|
239 static STLInfo g_stlinfo[] = |
|
240 { |
|
241 // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators |
|
242 { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, |
|
243 { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, |
|
244 { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
245 { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE }, |
|
246 { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE }, |
|
247 { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE }, |
|
248 { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE }, |
|
249 { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, |
|
250 { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, |
|
251 { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, |
|
252 { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, |
|
253 { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, |
|
254 { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE }, |
|
255 { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
256 { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
257 { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
258 { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
259 { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
260 { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
261 { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
262 { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
263 { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
264 { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
265 { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
266 { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
267 { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
268 { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
269 { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
270 { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
271 { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
272 { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
273 { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE }, |
|
274 { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE }, |
|
275 { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE }, |
|
276 { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
277 { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE }, |
|
278 { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, |
|
279 { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, |
|
280 { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, |
|
281 { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, |
|
282 { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, |
|
283 { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, |
|
284 { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, |
|
285 { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, |
|
286 { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, |
|
287 { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, |
|
288 { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, |
|
289 { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
290 { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
291 { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
292 { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
293 { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
294 { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
295 { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
296 { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
297 { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
298 { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
299 { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
300 { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
301 { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
302 { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
303 { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE }, |
|
304 { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE } |
|
305 }; |
|
306 |
|
307 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name) |
|
308 { |
|
309 Entry *memEntry = new Entry; |
|
310 memEntry->name = name; |
|
311 memEntry->type = type; |
|
312 memEntry->protection = Private; |
|
313 memEntry->section = Entry::VARIABLE_SEC; |
|
314 memEntry->brief = "STL member"; |
|
315 memEntry->hidden = FALSE; |
|
316 memEntry->artificial = TRUE; |
|
317 //memEntry->parent = root; |
|
318 //root->addSubEntry(memEntry); |
|
319 EntryNav *memEntryNav = new EntryNav(rootNav,memEntry); |
|
320 memEntryNav->setEntry(memEntry); |
|
321 rootNav->addChild(memEntryNav); |
|
322 } |
|
323 |
|
324 static void addSTLIterator(EntryNav *classEntryNav,const char *name) |
|
325 { |
|
326 Entry *iteratorClassEntry = new Entry; |
|
327 iteratorClassEntry->fileName = "[STL]"; |
|
328 iteratorClassEntry->startLine = 1; |
|
329 iteratorClassEntry->name = name; |
|
330 iteratorClassEntry->section = Entry::CLASS_SEC; |
|
331 iteratorClassEntry->brief = "STL iterator class"; |
|
332 iteratorClassEntry->hidden = FALSE; |
|
333 iteratorClassEntry->artificial= TRUE; |
|
334 EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry); |
|
335 iteratorClassEntryNav->setEntry(iteratorClassEntry); |
|
336 classEntryNav->addChild(iteratorClassEntryNav); |
|
337 } |
|
338 |
|
339 |
|
340 static void addSTLClasses(EntryNav *rootNav) |
|
341 { |
|
342 Entry *namespaceEntry = new Entry; |
|
343 namespaceEntry->fileName = "[STL]"; |
|
344 namespaceEntry->startLine = 1; |
|
345 //namespaceEntry->parent = rootNav->entry(); |
|
346 namespaceEntry->name = "std"; |
|
347 namespaceEntry->section = Entry::NAMESPACE_SEC; |
|
348 namespaceEntry->brief = "STL namespace"; |
|
349 namespaceEntry->hidden = FALSE; |
|
350 namespaceEntry->artificial= TRUE; |
|
351 //root->addSubEntry(namespaceEntry); |
|
352 EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry); |
|
353 namespaceEntryNav->setEntry(namespaceEntry); |
|
354 rootNav->addChild(namespaceEntryNav); |
|
355 |
|
356 STLInfo *info = g_stlinfo; |
|
357 while (info->className) |
|
358 { |
|
359 //printf("Adding STL class %s\n",info->className); |
|
360 QCString fullName = info->className; |
|
361 fullName.prepend("std::"); |
|
362 |
|
363 // add fake Entry for the class |
|
364 Entry *classEntry = new Entry; |
|
365 classEntry->fileName = "[STL]"; |
|
366 classEntry->startLine = 1; |
|
367 classEntry->name = fullName; |
|
368 //classEntry->parent = namespaceEntry; |
|
369 classEntry->section = Entry::CLASS_SEC; |
|
370 classEntry->brief = "STL class"; |
|
371 classEntry->hidden = FALSE; |
|
372 classEntry->artificial= TRUE; |
|
373 //namespaceEntry->addSubEntry(classEntry); |
|
374 EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry); |
|
375 classEntryNav->setEntry(classEntry); |
|
376 namespaceEntryNav->addChild(classEntryNav); |
|
377 |
|
378 // add template arguments to class |
|
379 if (info->templType1) |
|
380 { |
|
381 ArgumentList *al = new ArgumentList; |
|
382 Argument *a=new Argument; |
|
383 a->type="typename"; |
|
384 a->name=info->templType1; |
|
385 al->append(a); |
|
386 if (info->templType2) // another template argument |
|
387 { |
|
388 a=new Argument; |
|
389 a->type="typename"; |
|
390 a->name=info->templType2; |
|
391 al->append(a); |
|
392 } |
|
393 classEntry->tArgLists = new QList<ArgumentList>; |
|
394 classEntry->tArgLists->setAutoDelete(TRUE); |
|
395 classEntry->tArgLists->append(al); |
|
396 } |
|
397 // add member variables |
|
398 if (info->templName1) |
|
399 { |
|
400 addSTLMember(classEntryNav,info->templType1,info->templName1); |
|
401 } |
|
402 if (info->templName2) |
|
403 { |
|
404 addSTLMember(classEntryNav,info->templType2,info->templName2); |
|
405 } |
|
406 if (info->baseClass1) |
|
407 { |
|
408 classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal)); |
|
409 } |
|
410 if (info->baseClass2) |
|
411 { |
|
412 classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal)); |
|
413 } |
|
414 if (info->iterators) |
|
415 { |
|
416 // add iterator class |
|
417 addSTLIterator(classEntryNav,fullName+"::iterator"); |
|
418 addSTLIterator(classEntryNav,fullName+"::const_iterator"); |
|
419 addSTLIterator(classEntryNav,fullName+"::reverse_iterator"); |
|
420 addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator"); |
|
421 } |
|
422 info++; |
|
423 } |
|
424 } |
|
425 |
|
426 //---------------------------------------------------------------------------- |
|
427 |
|
428 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n, |
|
429 FileDef *fileScope=0); |
|
430 |
|
431 static void addPageToContext(PageDef *pd,EntryNav *rootNav) |
|
432 { |
|
433 if (rootNav->parent()) // add the page to it's scope |
|
434 { |
|
435 QCString scope = rootNav->parent()->name(); |
|
436 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC) |
|
437 { |
|
438 scope=substitute(scope,".","::"); |
|
439 } |
|
440 scope = stripAnonymousNamespaceScope(scope); |
|
441 scope+="::"+pd->name(); |
|
442 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope); |
|
443 if (d) |
|
444 { |
|
445 pd->setPageScope(d); |
|
446 } |
|
447 } |
|
448 } |
|
449 |
|
450 static void addRelatedPage(EntryNav *rootNav) |
|
451 { |
|
452 Entry *root = rootNav->entry(); |
|
453 GroupDef *gd=0; |
|
454 QListIterator<Grouping> gli(*root->groups); |
|
455 Grouping *g; |
|
456 for (;(g=gli.current());++gli) |
|
457 { |
|
458 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break; |
|
459 } |
|
460 //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd); |
|
461 QCString doc; |
|
462 if (root->brief.isEmpty()) |
|
463 { |
|
464 doc=root->doc+root->inbodyDocs; |
|
465 } |
|
466 else |
|
467 { |
|
468 doc=root->brief+"\n\n"+root->doc+root->inbodyDocs; |
|
469 } |
|
470 PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors, |
|
471 root->fileName,root->startLine, |
|
472 root->sli, |
|
473 gd,rootNav->tagInfo() |
|
474 ); |
|
475 if (pd) |
|
476 { |
|
477 pd->addSectionsToDefinition(root->anchors); |
|
478 addPageToContext(pd,rootNav); |
|
479 } |
|
480 } |
|
481 |
|
482 static void buildGroupListFiltered(EntryNav *rootNav,bool additional) |
|
483 { |
|
484 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty()) |
|
485 { |
|
486 //printf("Found group %s title=`%s type=%d'\n", |
|
487 // root->name.data(),root->type.data(),root->groupDocType); |
|
488 |
|
489 rootNav->loadEntry(g_storage); |
|
490 Entry *root = rootNav->entry(); |
|
491 |
|
492 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) || |
|
493 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional)) |
|
494 { |
|
495 GroupDef *gd; |
|
496 |
|
497 if ((gd=Doxygen::groupSDict->find(root->name))) |
|
498 { |
|
499 if ( !gd->hasGroupTitle() ) |
|
500 { |
|
501 gd->setGroupTitle( root->type ); |
|
502 } |
|
503 else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type ) |
|
504 { |
|
505 warn( root->fileName,root->startLine, |
|
506 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n", |
|
507 root->name.data(), root->type.data(), gd->groupTitle() ); |
|
508 } |
|
509 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
510 gd->setDocumentation( root->doc, root->docFile, root->docLine ); |
|
511 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine ); |
|
512 gd->addSectionsToDefinition(root->anchors); |
|
513 gd->setRefItems(root->sli); |
|
514 } |
|
515 else |
|
516 { |
|
517 if (rootNav->tagInfo()) |
|
518 { |
|
519 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName); |
|
520 gd->setReference(rootNav->tagInfo()->tagName); |
|
521 } |
|
522 else |
|
523 { |
|
524 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type); |
|
525 } |
|
526 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
527 gd->setDocumentation(root->doc,root->docFile,root->docLine); |
|
528 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine ); |
|
529 gd->addSectionsToDefinition(root->anchors); |
|
530 Doxygen::groupSDict->append(root->name,gd); |
|
531 gd->setRefItems(root->sli); |
|
532 } |
|
533 } |
|
534 |
|
535 rootNav->releaseEntry(); |
|
536 } |
|
537 if (rootNav->children()) |
|
538 { |
|
539 EntryNavListIterator eli(*rootNav->children()); |
|
540 EntryNav *e; |
|
541 for (;(e=eli.current());++eli) |
|
542 { |
|
543 buildGroupListFiltered(e,additional); |
|
544 } |
|
545 } |
|
546 } |
|
547 |
|
548 static void buildGroupList(EntryNav *rootNav) |
|
549 { |
|
550 // first process the @defgroups blocks |
|
551 buildGroupListFiltered(rootNav,FALSE); |
|
552 // then process the @addtogroup, @weakgroup blocks |
|
553 buildGroupListFiltered(rootNav,TRUE); |
|
554 } |
|
555 |
|
556 static void findGroupScope(EntryNav *rootNav) |
|
557 { |
|
558 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && |
|
559 rootNav->parent() && !rootNav->parent()->name().isEmpty()) |
|
560 { |
|
561 GroupDef *gd; |
|
562 if ((gd=Doxygen::groupSDict->find(rootNav->name()))) |
|
563 { |
|
564 QCString scope = rootNav->parent()->name(); |
|
565 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC) |
|
566 { |
|
567 scope=substitute(scope,".","::"); |
|
568 } |
|
569 scope = stripAnonymousNamespaceScope(scope); |
|
570 scope+="::"+gd->name(); |
|
571 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope); |
|
572 if (d) |
|
573 { |
|
574 gd->setGroupScope(d); |
|
575 } |
|
576 } |
|
577 } |
|
578 RECURSE_ENTRYTREE(findGroupScope,rootNav); |
|
579 } |
|
580 |
|
581 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional) |
|
582 { |
|
583 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty()) |
|
584 { |
|
585 rootNav->loadEntry(g_storage); |
|
586 Entry *root = rootNav->entry(); |
|
587 |
|
588 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) || |
|
589 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional)) |
|
590 { |
|
591 GroupDef *gd; |
|
592 if ((gd=Doxygen::groupSDict->find(root->name))) |
|
593 { |
|
594 //printf("adding %s to group %s\n",root->name.data(),gd->name().data()); |
|
595 addGroupToGroups(root,gd); |
|
596 } |
|
597 } |
|
598 |
|
599 rootNav->releaseEntry(); |
|
600 } |
|
601 if (rootNav->children()) |
|
602 { |
|
603 EntryNavListIterator eli(*rootNav->children()); |
|
604 EntryNav *e; |
|
605 for (;(e=eli.current());++eli) |
|
606 { |
|
607 organizeSubGroupsFiltered(e,additional); |
|
608 } |
|
609 } |
|
610 } |
|
611 |
|
612 static void organizeSubGroups(EntryNav *rootNav) |
|
613 { |
|
614 //printf("Defining groups\n"); |
|
615 // first process the @defgroups blocks |
|
616 organizeSubGroupsFiltered(rootNav,FALSE); |
|
617 //printf("Additional groups\n"); |
|
618 // then process the @addtogroup, @weakgroup blocks |
|
619 organizeSubGroupsFiltered(rootNav,TRUE); |
|
620 } |
|
621 |
|
622 //---------------------------------------------------------------------- |
|
623 |
|
624 static void buildFileList(EntryNav *rootNav) |
|
625 { |
|
626 if (((rootNav->section()==Entry::FILEDOC_SEC) || |
|
627 ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) && |
|
628 !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files |
|
629 ) |
|
630 { |
|
631 rootNav->loadEntry(g_storage); |
|
632 Entry *root = rootNav->entry(); |
|
633 |
|
634 bool ambig; |
|
635 FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig); |
|
636 //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd); |
|
637 if (fd && !ambig) |
|
638 { |
|
639 #if 0 |
|
640 if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) || |
|
641 (!root->brief.isEmpty() && !fd->briefDescription().isEmpty())) |
|
642 { |
|
643 warn( |
|
644 root->fileName,root->startLine, |
|
645 "Warning: file %s already documented. " |
|
646 "Skipping documentation.", |
|
647 root->name.data() |
|
648 ); |
|
649 } |
|
650 else |
|
651 #endif |
|
652 { |
|
653 //printf("Adding documentation!\n"); |
|
654 // using FALSE in setDocumentation is small hack to make sure a file |
|
655 // is documented even if a \file command is used without further |
|
656 // documentation |
|
657 fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE); |
|
658 fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
659 fd->addSectionsToDefinition(root->anchors); |
|
660 fd->setRefItems(root->sli); |
|
661 QListIterator<Grouping> gli(*root->groups); |
|
662 Grouping *g; |
|
663 for (;(g=gli.current());++gli) |
|
664 { |
|
665 GroupDef *gd=0; |
|
666 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) |
|
667 { |
|
668 gd->addFile(fd); |
|
669 //printf("File %s: in group %s\n",fd->name().data(),s->data()); |
|
670 } |
|
671 } |
|
672 } |
|
673 } |
|
674 // NOTE: if OUTPUT_INCLUDES is true then we will see files that are not in |
|
675 // the INPUT list |
|
676 else if (!Config_getBool("OUTPUT_INCLUDES")) |
|
677 { |
|
678 const char *fn = root->fileName.data(); |
|
679 QCString text; |
|
680 text.sprintf("Warning: the name `%s' supplied as " |
|
681 "the second argument in the \\file statement ", |
|
682 root->name.data() |
|
683 ); |
|
684 if (ambig) // name is ambigious |
|
685 { |
|
686 text+="matches the following input files:\n"; |
|
687 text+=showFileDefMatches(Doxygen::inputNameDict,root->name); |
|
688 text+="Please use a more specific name by " |
|
689 "including a (larger) part of the path!"; |
|
690 } |
|
691 else // name is not an input file |
|
692 { |
|
693 text+="is not an input file"; |
|
694 } |
|
695 warn(fn,root->startLine,text); |
|
696 } |
|
697 |
|
698 rootNav->releaseEntry(); |
|
699 } |
|
700 RECURSE_ENTRYTREE(buildFileList,rootNav); |
|
701 } |
|
702 |
|
703 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root) |
|
704 { |
|
705 if ( |
|
706 (!root->doc.stripWhiteSpace().isEmpty() || |
|
707 !root->brief.stripWhiteSpace().isEmpty() || |
|
708 Config_getBool("EXTRACT_ALL") |
|
709 ) && root->protection!=Private |
|
710 ) |
|
711 { |
|
712 //printf(">>>>>> includeFile=%s\n",root->includeFile.data()); |
|
713 |
|
714 bool local=Config_getBool("FORCE_LOCAL_INCLUDES"); |
|
715 QCString includeFile = root->includeFile; |
|
716 if (!includeFile.isEmpty() && includeFile.at(0)=='"') |
|
717 { |
|
718 local = TRUE; |
|
719 includeFile=includeFile.mid(1,includeFile.length()-2); |
|
720 } |
|
721 else if (!includeFile.isEmpty() && includeFile.at(0)=='<') |
|
722 { |
|
723 local = FALSE; |
|
724 includeFile=includeFile.mid(1,includeFile.length()-2); |
|
725 } |
|
726 |
|
727 bool ambig; |
|
728 FileDef *fd=0; |
|
729 // see if we need to include a verbatim copy of the header file |
|
730 //printf("root->includeFile=%s\n",root->includeFile.data()); |
|
731 if (!includeFile.isEmpty() && |
|
732 (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0 |
|
733 ) |
|
734 { // explicit request |
|
735 QCString text; |
|
736 text.sprintf("Warning: the name `%s' supplied as " |
|
737 "the argument of the \\class, \\struct, \\union, or \\include command ", |
|
738 includeFile.data() |
|
739 ); |
|
740 if (ambig) // name is ambigious |
|
741 { |
|
742 text+="matches the following input files:\n"; |
|
743 text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile); |
|
744 text+="Please use a more specific name by " |
|
745 "including a (larger) part of the path!"; |
|
746 } |
|
747 else // name is not an input file |
|
748 { |
|
749 text+="is not an input file"; |
|
750 } |
|
751 warn(root->fileName,root->startLine,text); |
|
752 } |
|
753 else if (includeFile.isEmpty() && ifd && |
|
754 // see if the file extension makes sense |
|
755 guessSection(ifd->name())==Entry::HEADER_SEC) |
|
756 { // implicit assumption |
|
757 fd=ifd; |
|
758 } |
|
759 |
|
760 // if a file is found, we mark it as a source file. |
|
761 if (fd) |
|
762 { |
|
763 QCString iName = !root->includeName.isEmpty() ? |
|
764 root->includeName : includeFile; |
|
765 if (!iName.isEmpty()) // user specified include file |
|
766 { |
|
767 if (iName.at(0)=='<') local=FALSE; // explicit override |
|
768 if (iName.at(0)=='"' || iName.at(0)=='<') |
|
769 { |
|
770 iName=iName.mid(1,iName.length()-2); // strip quotes or brackets |
|
771 } |
|
772 if (iName.isEmpty()) |
|
773 { |
|
774 iName=fd->name(); |
|
775 } |
|
776 } |
|
777 else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) |
|
778 { |
|
779 iName=stripFromIncludePath(fd->absFilePath()); |
|
780 } |
|
781 else // use name of the file containing the class definition |
|
782 { |
|
783 iName=fd->name(); |
|
784 } |
|
785 if (fd->generateSourceFile()) // generate code for header |
|
786 { |
|
787 cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty()); |
|
788 } |
|
789 else // put #include in the class documentation without link |
|
790 { |
|
791 cd->setIncludeFile(0,iName,local,TRUE); |
|
792 } |
|
793 } |
|
794 } |
|
795 } |
|
796 |
|
797 #if 0 |
|
798 static bool addNamespace(Entry *root,ClassDef *cd) |
|
799 { |
|
800 // see if this class is defined inside a namespace |
|
801 if (root->section & Entry::COMPOUND_MASK) |
|
802 { |
|
803 Entry *e = root->parent; |
|
804 while (e) |
|
805 { |
|
806 if (e->section==Entry::NAMESPACE_SEC) |
|
807 { |
|
808 NamespaceDef *nd=0; |
|
809 QCString nsName = stripAnonymousNamespaceScope(e->name); |
|
810 //printf("addNameSpace() trying: %s\n",nsName.data()); |
|
811 if (!nsName.isEmpty() && nsName.at(0)!='@' && |
|
812 (nd=getResolvedNamespace(nsName)) |
|
813 ) |
|
814 { |
|
815 cd->setNamespace(nd); |
|
816 cd->setOuterScope(nd); |
|
817 nd->insertClass(cd); |
|
818 return TRUE; |
|
819 } |
|
820 } |
|
821 e=e->parent; |
|
822 } |
|
823 } |
|
824 return FALSE; |
|
825 } |
|
826 #endif |
|
827 |
|
828 #if 0 |
|
829 static Definition *findScope(Entry *root,int level=0) |
|
830 { |
|
831 if (root==0) return 0; |
|
832 //printf("start findScope name=%s\n",root->name.data()); |
|
833 Definition *result=0; |
|
834 if (root->section&Entry::SCOPE_MASK) |
|
835 { |
|
836 result = findScope(root->parent,level+1); // traverse to the root of the tree |
|
837 if (result) |
|
838 { |
|
839 //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level); |
|
840 // TODO: look at template arguments |
|
841 result = result->findInnerCompound(root->name); |
|
842 } |
|
843 else // reached the global scope |
|
844 { |
|
845 // TODO: look at template arguments |
|
846 result = Doxygen::globalScope->findInnerCompound(root->name); |
|
847 //printf("Found in globalScope %s at level %d\n",result->name().data(),level); |
|
848 } |
|
849 } |
|
850 //printf("end findScope(%s,%d)=%s\n",root->name.data(), |
|
851 // level,result==0 ? "<none>" : result->name().data()); |
|
852 return result; |
|
853 } |
|
854 #endif |
|
855 |
|
856 /*! returns the Definition object belonging to the first \a level levels of |
|
857 * full qualified name \a name. Creates an artificial scope if the scope is |
|
858 * not found and set the parent/child scope relation if the scope is found. |
|
859 */ |
|
860 static Definition *buildScopeFromQualifiedName(const QCString name,int level) |
|
861 { |
|
862 int i=0; |
|
863 int p=0,l; |
|
864 Definition *prevScope=Doxygen::globalScope; |
|
865 QCString fullScope; |
|
866 while (i<level) |
|
867 { |
|
868 int idx=getScopeFragment(name,p,&l); |
|
869 QCString nsName = name.mid(idx,l); |
|
870 if (nsName.isEmpty()) return prevScope; |
|
871 if (!fullScope.isEmpty()) fullScope+="::"; |
|
872 fullScope+=nsName; |
|
873 NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope); |
|
874 Definition *innerScope = nd; |
|
875 ClassDef *cd=0; |
|
876 if (nd==0) cd = getClass(fullScope); |
|
877 if (nd==0 && cd) // scope is a class |
|
878 { |
|
879 innerScope = cd; |
|
880 } |
|
881 else if (nd==0 && cd==0) // scope is not known! |
|
882 { |
|
883 // introduce bogus namespace |
|
884 //printf("++ adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data()); |
|
885 nd=new NamespaceDef( |
|
886 "[generated]",1,fullScope); |
|
887 |
|
888 // add namespace to the list |
|
889 Doxygen::namespaceSDict->inSort(fullScope,nd); |
|
890 innerScope = nd; |
|
891 } |
|
892 else // scope is a namespace |
|
893 { |
|
894 } |
|
895 // make the parent/child scope relation |
|
896 prevScope->addInnerCompound(innerScope); |
|
897 innerScope->setOuterScope(prevScope); |
|
898 // proceed to the next scope fragment |
|
899 p=idx+l+2; |
|
900 prevScope=innerScope; |
|
901 i++; |
|
902 } |
|
903 return prevScope; |
|
904 } |
|
905 |
|
906 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n, |
|
907 FileDef *fileScope) |
|
908 { |
|
909 //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data()); |
|
910 Definition *resultScope=startScope; |
|
911 if (resultScope==0) resultScope=Doxygen::globalScope; |
|
912 QCString scope=stripTemplateSpecifiersFromScope(n,FALSE); |
|
913 int l1=0,i1; |
|
914 i1=getScopeFragment(scope,0,&l1); |
|
915 if (i1==-1) |
|
916 { |
|
917 //printf(">no fragments!\n"); |
|
918 return resultScope; |
|
919 } |
|
920 int p=i1+l1,l2=0,i2; |
|
921 while ((i2=getScopeFragment(scope,p,&l2))!=-1) |
|
922 { |
|
923 QCString nestedNameSpecifier = scope.mid(i1,l1); |
|
924 Definition *orgScope = resultScope; |
|
925 //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data()); |
|
926 resultScope = resultScope->findInnerCompound(nestedNameSpecifier); |
|
927 //printf(" resultScope=%p\n",resultScope); |
|
928 if (resultScope==0) |
|
929 { |
|
930 NamespaceSDict *usedNamespaces; |
|
931 if (orgScope==Doxygen::globalScope && fileScope && |
|
932 (usedNamespaces = fileScope->getUsedNamespaces())) |
|
933 // also search for used namespaces |
|
934 { |
|
935 NamespaceSDict::Iterator ni(*usedNamespaces); |
|
936 NamespaceDef *nd; |
|
937 for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni) |
|
938 { |
|
939 // restart search within the used namespace |
|
940 resultScope = findScopeFromQualifiedName(nd,n,fileScope); |
|
941 } |
|
942 if (resultScope) |
|
943 { |
|
944 // for a nested class A::I in used namespace N, we get |
|
945 // N::A::I while looking for A, so we should compare |
|
946 // resultScope->name() against scope.left(i2+l2) |
|
947 //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data()); |
|
948 if (rightScopeMatch(resultScope->name(),scope.left(i2+l2))) |
|
949 { |
|
950 break; |
|
951 } |
|
952 goto nextFragment; |
|
953 } |
|
954 } |
|
955 |
|
956 // also search for used classes. Complication: we haven't been able |
|
957 // to put them in the right scope yet, because we are still resolving |
|
958 // the scope relations! |
|
959 // Therefore loop through all used classes and see if there is a right |
|
960 // scope match between the used class and nestedNameSpecifier. |
|
961 QDictIterator<FileDef> ui(g_usingDeclarations); |
|
962 FileDef *usedFd; |
|
963 for (ui.toFirst();(usedFd=ui.current());++ui) |
|
964 { |
|
965 //printf("Checking using class %s\n",ui.currentKey()); |
|
966 if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier)) |
|
967 { |
|
968 // ui.currentKey() is the fully qualified name of nestedNameSpecifier |
|
969 // so use this instead. |
|
970 QCString fqn = QCString(ui.currentKey())+ |
|
971 scope.right(scope.length()-p); |
|
972 resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::")); |
|
973 //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope); |
|
974 if (resultScope) |
|
975 { |
|
976 //printf("> Match! resultScope=%s\n",resultScope->name().data()); |
|
977 return resultScope; |
|
978 } |
|
979 } |
|
980 } |
|
981 |
|
982 //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data()); |
|
983 return 0; |
|
984 } |
|
985 nextFragment: |
|
986 i1=i2; |
|
987 l1=l2; |
|
988 p=i2+l2; |
|
989 } |
|
990 //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data()); |
|
991 return resultScope; |
|
992 } |
|
993 |
|
994 ArgumentList *getTemplateArgumentsFromName( |
|
995 const QCString &name, |
|
996 const QList<ArgumentList> *tArgLists) |
|
997 { |
|
998 if (tArgLists==0) return 0; |
|
999 |
|
1000 QListIterator<ArgumentList> ali(*tArgLists); |
|
1001 // for each scope fragment, check if it is a template and advance through |
|
1002 // the list if so. |
|
1003 int i,p=0; |
|
1004 while ((i=name.find("::",p))!=-1) |
|
1005 { |
|
1006 NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i)); |
|
1007 if (nd==0) |
|
1008 { |
|
1009 ClassDef *cd = getClass(name.left(i)); |
|
1010 if (cd) |
|
1011 { |
|
1012 if (cd->templateArguments()) |
|
1013 { |
|
1014 ++ali; |
|
1015 } |
|
1016 } |
|
1017 } |
|
1018 p=i+2; |
|
1019 } |
|
1020 return ali.current(); |
|
1021 } |
|
1022 |
|
1023 static ClassDef::CompoundType convertToCompoundType(int section,int specifier) |
|
1024 { |
|
1025 ClassDef::CompoundType sec=ClassDef::Class; |
|
1026 if (specifier&Entry::Struct) |
|
1027 sec=ClassDef::Struct; |
|
1028 else if (specifier&Entry::Union) |
|
1029 sec=ClassDef::Union; |
|
1030 else if (specifier&Entry::Interface) |
|
1031 sec=ClassDef::Interface; |
|
1032 else if (specifier&Entry::Protocol) |
|
1033 sec=ClassDef::Protocol; |
|
1034 else if (specifier&Entry::Category) |
|
1035 sec=ClassDef::Category; |
|
1036 else if (specifier&Entry::Exception) |
|
1037 sec=ClassDef::Exception; |
|
1038 |
|
1039 switch(section) |
|
1040 { |
|
1041 //case Entry::UNION_SEC: |
|
1042 case Entry::UNIONDOC_SEC: |
|
1043 sec=ClassDef::Union; |
|
1044 break; |
|
1045 //case Entry::STRUCT_SEC: |
|
1046 case Entry::STRUCTDOC_SEC: |
|
1047 sec=ClassDef::Struct; |
|
1048 break; |
|
1049 //case Entry::INTERFACE_SEC: |
|
1050 case Entry::INTERFACEDOC_SEC: |
|
1051 sec=ClassDef::Interface; |
|
1052 break; |
|
1053 //case Entry::PROTOCOL_SEC: |
|
1054 case Entry::PROTOCOLDOC_SEC: |
|
1055 sec=ClassDef::Protocol; |
|
1056 break; |
|
1057 //case Entry::CATEGORY_SEC: |
|
1058 case Entry::CATEGORYDOC_SEC: |
|
1059 sec=ClassDef::Category; |
|
1060 break; |
|
1061 //case Entry::EXCEPTION_SEC: |
|
1062 case Entry::EXCEPTIONDOC_SEC: |
|
1063 sec=ClassDef::Exception; |
|
1064 break; |
|
1065 } |
|
1066 return sec; |
|
1067 } |
|
1068 |
|
1069 |
|
1070 static void addClassToContext(EntryNav *rootNav) |
|
1071 { |
|
1072 //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data()); |
|
1073 rootNav->loadEntry(g_storage); |
|
1074 Entry *root = rootNav->entry(); |
|
1075 |
|
1076 //NamespaceDef *nd = 0; |
|
1077 FileDef *fd = rootNav->fileDef(); |
|
1078 |
|
1079 QCString scName; |
|
1080 if (rootNav->parent()->section()&Entry::SCOPE_MASK) |
|
1081 { |
|
1082 scName=rootNav->parent()->name(); |
|
1083 } |
|
1084 // name without parent's scope |
|
1085 QCString fullName = root->name; |
|
1086 |
|
1087 // strip off any template parameters (but not those for specializations) |
|
1088 fullName=stripTemplateSpecifiersFromScope(fullName); |
|
1089 |
|
1090 // name with scope (if not present already) |
|
1091 QCString qualifiedName = fullName; |
|
1092 if (!scName.isEmpty() && !leftScopeMatch(fullName,scName)) |
|
1093 { |
|
1094 qualifiedName.prepend(scName+"::"); |
|
1095 } |
|
1096 |
|
1097 // see if we already found the class before |
|
1098 ClassDef *cd = getClass(qualifiedName); |
|
1099 |
|
1100 Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n", |
|
1101 cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd); |
|
1102 |
|
1103 if (cd) |
|
1104 { |
|
1105 fullName=cd->name(); |
|
1106 Debug::print(Debug::Classes,0," Existing class %s!\n",cd->name().data()); |
|
1107 //if (cd->templateArguments()==0) |
|
1108 //{ |
|
1109 // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data()); |
|
1110 // cd->setTemplateArguments(tArgList); |
|
1111 //} |
|
1112 |
|
1113 cd->setDocumentation(root->doc,root->docFile,root->docLine); |
|
1114 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1115 |
|
1116 if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1) |
|
1117 { |
|
1118 cd->setBodySegment(root->bodyLine,root->endBodyLine); |
|
1119 cd->setBodyDef(fd); |
|
1120 } |
|
1121 //cd->setName(fullName); // change name to match docs |
|
1122 |
|
1123 if (cd->templateArguments()==0) |
|
1124 { |
|
1125 // this happens if a template class declared with @class is found |
|
1126 // before the actual definition. |
|
1127 ArgumentList *tArgList = |
|
1128 getTemplateArgumentsFromName(cd->name(),root->tArgLists); |
|
1129 cd->setTemplateArguments(tArgList); |
|
1130 } |
|
1131 |
|
1132 cd->setCompoundType(convertToCompoundType(root->section,root->spec)); |
|
1133 } |
|
1134 else // new class |
|
1135 { |
|
1136 ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec); |
|
1137 |
|
1138 QCString className; |
|
1139 QCString namespaceName; |
|
1140 extractNamespaceName(fullName,className,namespaceName); |
|
1141 |
|
1142 //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n", |
|
1143 // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data()); |
|
1144 |
|
1145 QCString tagName; |
|
1146 QCString refFileName; |
|
1147 if (rootNav->tagInfo()) |
|
1148 { |
|
1149 tagName = rootNav->tagInfo()->tagName; |
|
1150 refFileName = rootNav->tagInfo()->fileName; |
|
1151 } |
|
1152 cd=new ClassDef(root->fileName,root->startLine,fullName,sec, |
|
1153 tagName,refFileName); |
|
1154 Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d\n", |
|
1155 fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1); |
|
1156 cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition |
|
1157 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1158 cd->setIsObjectiveC(root->objc); |
|
1159 cd->setHidden(root->hidden); |
|
1160 cd->setArtificial(root->artificial); |
|
1161 cd->setTypeConstraints(root->typeConstr); |
|
1162 //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data()); |
|
1163 |
|
1164 ArgumentList *tArgList = |
|
1165 getTemplateArgumentsFromName(fullName,root->tArgLists); |
|
1166 //printf("class %s template args=%s\n",fullName.data(), |
|
1167 // tArgList ? tempArgListToString(tArgList).data() : "<none>"); |
|
1168 cd->setTemplateArguments(tArgList); |
|
1169 cd->setProtection(root->protection); |
|
1170 cd->setIsStatic(root->stat); |
|
1171 |
|
1172 // file definition containing the class cd |
|
1173 cd->setBodySegment(root->bodyLine,root->endBodyLine); |
|
1174 cd->setBodyDef(fd); |
|
1175 |
|
1176 // see if the class is found inside a namespace |
|
1177 //bool found=addNamespace(root,cd); |
|
1178 |
|
1179 |
|
1180 // the empty string test is needed for extract all case |
|
1181 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1182 cd->insertUsedFile(root->fileName); |
|
1183 |
|
1184 // add class to the list |
|
1185 //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data()); |
|
1186 Doxygen::classSDict->append(fullName,cd); |
|
1187 |
|
1188 } |
|
1189 |
|
1190 cd->addSectionsToDefinition(root->anchors); |
|
1191 if (!root->subGrouping) cd->setSubGrouping(FALSE); |
|
1192 if (cd->hasDocumentation()) |
|
1193 { |
|
1194 addIncludeFile(cd,fd,root); |
|
1195 } |
|
1196 if (fd && (root->section & Entry::COMPOUND_MASK)) |
|
1197 { |
|
1198 //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n", |
|
1199 // cd->name().data(), |
|
1200 // fd->name().data(), |
|
1201 // root->fileName.data() |
|
1202 // ); |
|
1203 cd->setFileDef(fd); |
|
1204 fd->insertClass(cd); |
|
1205 } |
|
1206 addClassToGroups(root,cd); |
|
1207 cd->setRefItems(root->sli); |
|
1208 |
|
1209 rootNav->releaseEntry(); |
|
1210 } |
|
1211 |
|
1212 //---------------------------------------------------------------------- |
|
1213 // build a list of all classes mentioned in the documentation |
|
1214 // and all classes that have a documentation block before their definition. |
|
1215 static void buildClassList(EntryNav *rootNav) |
|
1216 { |
|
1217 if ( |
|
1218 ((rootNav->section() & Entry::COMPOUND_MASK) || |
|
1219 rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty() |
|
1220 ) |
|
1221 { |
|
1222 addClassToContext(rootNav); |
|
1223 } |
|
1224 RECURSE_ENTRYTREE(buildClassList,rootNav); |
|
1225 } |
|
1226 |
|
1227 static void buildClassDocList(EntryNav *rootNav) |
|
1228 { |
|
1229 if ( |
|
1230 (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty() |
|
1231 ) |
|
1232 { |
|
1233 addClassToContext(rootNav); |
|
1234 } |
|
1235 RECURSE_ENTRYTREE(buildClassDocList,rootNav); |
|
1236 } |
|
1237 |
|
1238 static void resolveClassNestingRelations() |
|
1239 { |
|
1240 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
1241 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; |
|
1242 |
|
1243 bool done=FALSE; |
|
1244 int iteration=0; |
|
1245 while (!done) |
|
1246 { |
|
1247 done=TRUE; |
|
1248 ++iteration; |
|
1249 ClassDef *cd=0; |
|
1250 for (cli.toFirst();(cd=cli.current());++cli) |
|
1251 { |
|
1252 if (!cd->visited) |
|
1253 { |
|
1254 QCString name = stripAnonymousNamespaceScope(cd->name()); |
|
1255 //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration); |
|
1256 // also add class to the correct structural context |
|
1257 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope, |
|
1258 name,cd->getFileDef()); |
|
1259 if (d) |
|
1260 { |
|
1261 //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration); |
|
1262 d->addInnerCompound(cd); |
|
1263 cd->setOuterScope(d); |
|
1264 cd->visited=TRUE; |
|
1265 done=FALSE; |
|
1266 } |
|
1267 //else |
|
1268 //{ |
|
1269 // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration); |
|
1270 //} |
|
1271 } |
|
1272 } |
|
1273 } |
|
1274 |
|
1275 //give warnings for unresolved compounds |
|
1276 ClassDef *cd=0; |
|
1277 for (cli.toFirst();(cd=cli.current());++cli) |
|
1278 { |
|
1279 if (!cd->visited) |
|
1280 { |
|
1281 QCString name = stripAnonymousNamespaceScope(cd->name()); |
|
1282 //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration); |
|
1283 /// create the scope artificially |
|
1284 // anyway, so we can at least relate scopes properly. |
|
1285 Definition *d = buildScopeFromQualifiedName(name,name.contains("::")); |
|
1286 if (d!=cd && !cd->getDefFileName().isEmpty()) |
|
1287 // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; } |
|
1288 // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found! |
|
1289 // also avoid warning for stuff imported via a tagfile. |
|
1290 { |
|
1291 d->addInnerCompound(cd); |
|
1292 cd->setOuterScope(d); |
|
1293 warn(cd->getDefFileName(),cd->getDefLine(), |
|
1294 "Warning: Internal inconsistency: scope for class %s not " |
|
1295 "found!",name.data() |
|
1296 ); |
|
1297 } |
|
1298 } |
|
1299 } |
|
1300 } |
|
1301 |
|
1302 |
|
1303 //---------------------------------------------------------------------- |
|
1304 // build a list of all namespaces mentioned in the documentation |
|
1305 // and all namespaces that have a documentation block before their definition. |
|
1306 static void buildNamespaceList(EntryNav *rootNav) |
|
1307 { |
|
1308 if ( |
|
1309 (rootNav->section()==Entry::NAMESPACE_SEC || |
|
1310 rootNav->section()==Entry::NAMESPACEDOC_SEC || |
|
1311 rootNav->section()==Entry::PACKAGEDOC_SEC |
|
1312 ) && |
|
1313 !rootNav->name().isEmpty() |
|
1314 ) |
|
1315 { |
|
1316 rootNav->loadEntry(g_storage); |
|
1317 Entry *root = rootNav->entry(); |
|
1318 |
|
1319 //printf("** buildNamespaceList(%s)\n",root->name.data()); |
|
1320 |
|
1321 QCString fName = root->name; |
|
1322 if (root->section==Entry::PACKAGEDOC_SEC) |
|
1323 { |
|
1324 fName=substitute(fName,".","::"); |
|
1325 } |
|
1326 |
|
1327 QCString fullName = stripAnonymousNamespaceScope(fName); |
|
1328 if (!fullName.isEmpty()) |
|
1329 { |
|
1330 //printf("Found namespace %s in %s at line %d\n",root->name.data(), |
|
1331 // root->fileName.data(), root->startLine); |
|
1332 NamespaceDef *nd; |
|
1333 if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace |
|
1334 { |
|
1335 #if 0 |
|
1336 if (!root->doc.isEmpty() || !root->brief.isEmpty()) // block contains docs |
|
1337 { |
|
1338 if (nd->documentation().isEmpty() && !root->doc.isEmpty()) |
|
1339 { |
|
1340 #endif |
|
1341 nd->setDocumentation(root->doc,root->docFile,root->docLine); |
|
1342 nd->setName(fullName); // change name to match docs |
|
1343 nd->addSectionsToDefinition(root->anchors); |
|
1344 #if 0 |
|
1345 } |
|
1346 else if (!nd->documentation().isEmpty() && !root->doc.isEmpty()) |
|
1347 { |
|
1348 warn( |
|
1349 root->fileName,root->startLine, |
|
1350 "Warning: namespace %s already has a detailed description found in file %s at line %d. " |
|
1351 "Skipping the documentation found here.", |
|
1352 fullName.data(),nd->docFile().data(),nd->docLine()); |
|
1353 } |
|
1354 if (nd->briefDescription().isEmpty() && !root->brief.isEmpty()) |
|
1355 { |
|
1356 #endif |
|
1357 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1358 #if 0 |
|
1359 nd->setName(fullName); // change name to match docs |
|
1360 } |
|
1361 else if (!nd->briefDescription().isEmpty() && !root->brief.isEmpty()) |
|
1362 { |
|
1363 warn(root->fileName,root->startLine, |
|
1364 "Warning: namespace %s already has a brief description found in file %s at line %d. " |
|
1365 "Skipping the documentation found here.", |
|
1366 fullName.data(),nd->docFile().data(),nd->docLine() |
|
1367 ); |
|
1368 } |
|
1369 } |
|
1370 #endif |
|
1371 |
|
1372 // file definition containing the namespace nd |
|
1373 FileDef *fd=rootNav->fileDef(); |
|
1374 // insert the namespace in the file definition |
|
1375 if (fd) fd->insertNamespace(nd); |
|
1376 addNamespaceToGroups(root,nd); |
|
1377 nd->setRefItems(root->sli); |
|
1378 } |
|
1379 else // fresh namespace |
|
1380 { |
|
1381 QCString tagName; |
|
1382 QCString tagFileName; |
|
1383 if (rootNav->tagInfo()) |
|
1384 { |
|
1385 tagName=rootNav->tagInfo()->tagName; |
|
1386 tagFileName=rootNav->tagInfo()->fileName; |
|
1387 } |
|
1388 //printf("++ new namespace %d\n",fullName.data()); |
|
1389 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName); |
|
1390 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition |
|
1391 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1392 nd->addSectionsToDefinition(root->anchors); |
|
1393 nd->setHidden(root->hidden); |
|
1394 nd->setArtificial(root->artificial); |
|
1395 |
|
1396 //printf("Adding namespace to group\n"); |
|
1397 addNamespaceToGroups(root,nd); |
|
1398 nd->setRefItems(root->sli); |
|
1399 |
|
1400 // file definition containing the namespace nd |
|
1401 FileDef *fd=rootNav->fileDef(); |
|
1402 // insert the namespace in the file definition |
|
1403 if (fd) fd->insertNamespace(nd); |
|
1404 |
|
1405 // the empty string test is needed for extract all case |
|
1406 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1407 nd->insertUsedFile(root->fileName); |
|
1408 nd->setBodySegment(root->bodyLine,root->endBodyLine); |
|
1409 nd->setBodyDef(fd); |
|
1410 // add class to the list |
|
1411 Doxygen::namespaceSDict->inSort(fullName,nd); |
|
1412 |
|
1413 // also add namespace to the correct structural context |
|
1414 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName); |
|
1415 //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>"); |
|
1416 if (d==0) // we didn't find anything, create the scope artificially |
|
1417 // anyway, so we can at least relate scopes properly. |
|
1418 { |
|
1419 Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::")); |
|
1420 d->addInnerCompound(nd); |
|
1421 nd->setOuterScope(d); |
|
1422 // TODO: Due to the order in which the tag file is written |
|
1423 // a nested class can be found before its parent! |
|
1424 } |
|
1425 else |
|
1426 { |
|
1427 d->addInnerCompound(nd); |
|
1428 nd->setOuterScope(d); |
|
1429 } |
|
1430 } |
|
1431 } |
|
1432 |
|
1433 rootNav->releaseEntry(); |
|
1434 } |
|
1435 RECURSE_ENTRYTREE(buildNamespaceList,rootNav); |
|
1436 } |
|
1437 |
|
1438 //---------------------------------------------------------------------- |
|
1439 |
|
1440 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl, |
|
1441 const QCString &name) |
|
1442 { |
|
1443 NamespaceDef *usingNd =0; |
|
1444 if (unl) |
|
1445 { |
|
1446 //printf("Found namespace dict %d\n",unl->count()); |
|
1447 NamespaceSDict::Iterator unli(*unl); |
|
1448 NamespaceDef *und; |
|
1449 for (unli.toFirst();(und=unli.current());++unli) |
|
1450 { |
|
1451 QCString uScope=und->name()+"::"; |
|
1452 usingNd = getResolvedNamespace(uScope+name); |
|
1453 //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd); |
|
1454 } |
|
1455 } |
|
1456 return usingNd; |
|
1457 } |
|
1458 |
|
1459 static void findUsingDirectives(EntryNav *rootNav) |
|
1460 { |
|
1461 if (rootNav->section()==Entry::USINGDIR_SEC) |
|
1462 { |
|
1463 rootNav->loadEntry(g_storage); |
|
1464 Entry *root = rootNav->entry(); |
|
1465 |
|
1466 //printf("Found using directive %s at line %d of %s\n", |
|
1467 // root->name.data(),root->startLine,root->fileName.data()); |
|
1468 QCString name=substitute(root->name,".","::"); |
|
1469 if (!name.isEmpty()) |
|
1470 { |
|
1471 NamespaceDef *usingNd = 0; |
|
1472 NamespaceDef *nd = 0; |
|
1473 FileDef *fd = rootNav->fileDef(); |
|
1474 QCString nsName; |
|
1475 |
|
1476 // see if the using statement was found inside a namespace or inside |
|
1477 // the global file scope. |
|
1478 if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC && |
|
1479 (fd==0 || !fd->isJava()) // not a .java file |
|
1480 ) |
|
1481 { |
|
1482 nsName=stripAnonymousNamespaceScope(rootNav->parent()->name()); |
|
1483 if (!nsName.isEmpty()) |
|
1484 { |
|
1485 nd = getResolvedNamespace(nsName); |
|
1486 } |
|
1487 } |
|
1488 |
|
1489 // find the scope in which the `using' namespace is defined by prepending |
|
1490 // the possible scopes in which the using statement was found, starting |
|
1491 // with the most inner scope and going to the most outer scope (i.e. |
|
1492 // file scope). |
|
1493 int scopeOffset = nsName.length(); |
|
1494 do |
|
1495 { |
|
1496 QCString scope=scopeOffset>0 ? |
|
1497 nsName.left(scopeOffset)+"::" : QCString(); |
|
1498 usingNd = getResolvedNamespace(scope+name); |
|
1499 //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd); |
|
1500 if (scopeOffset==0) |
|
1501 { |
|
1502 scopeOffset=-1; |
|
1503 } |
|
1504 else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1) |
|
1505 { |
|
1506 scopeOffset=0; |
|
1507 } |
|
1508 } while (scopeOffset>=0 && usingNd==0); |
|
1509 |
|
1510 if (usingNd==0 && nd) // not found, try used namespaces in this scope |
|
1511 // or in one of the parent namespace scopes |
|
1512 { |
|
1513 NamespaceDef *pnd = nd; |
|
1514 while (pnd && usingNd==0) |
|
1515 { |
|
1516 // also try with one of the used namespaces found earlier |
|
1517 usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name); |
|
1518 |
|
1519 // goto the parent |
|
1520 Definition *s = pnd->getOuterScope(); |
|
1521 if (s && s->definitionType()==Definition::TypeNamespace) |
|
1522 { |
|
1523 pnd = (NamespaceDef*)s; |
|
1524 } |
|
1525 else |
|
1526 { |
|
1527 pnd = 0; |
|
1528 } |
|
1529 } |
|
1530 } |
|
1531 if (usingNd==0 && fd) // still nothing, also try used namespace in the |
|
1532 // global scope |
|
1533 { |
|
1534 usingNd = findUsedNamespace(fd->getUsedNamespaces(),name); |
|
1535 } |
|
1536 |
|
1537 //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>"); |
|
1538 |
|
1539 // add the namespace the correct scope |
|
1540 if (usingNd) |
|
1541 { |
|
1542 //printf("using fd=%p nd=%p\n",fd,nd); |
|
1543 if (nd) |
|
1544 { |
|
1545 //printf("Inside namespace %s\n",nd->name().data()); |
|
1546 nd->addUsingDirective(usingNd); |
|
1547 } |
|
1548 else if (fd) |
|
1549 { |
|
1550 //printf("Inside file %s\n",fd->name().data()); |
|
1551 fd->addUsingDirective(usingNd); |
|
1552 } |
|
1553 } |
|
1554 else // unknown namespace, but add it anyway. |
|
1555 { |
|
1556 //printf("++ new unknown namespace %s\n",name.data()); |
|
1557 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name); |
|
1558 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition |
|
1559 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1560 nd->addSectionsToDefinition(root->anchors); |
|
1561 //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden); |
|
1562 nd->setHidden(root->hidden); |
|
1563 nd->setArtificial(TRUE); |
|
1564 |
|
1565 QListIterator<Grouping> gli(*root->groups); |
|
1566 Grouping *g; |
|
1567 for (;(g=gli.current());++gli) |
|
1568 { |
|
1569 GroupDef *gd=0; |
|
1570 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) |
|
1571 gd->addNamespace(nd); |
|
1572 } |
|
1573 |
|
1574 // insert the namespace in the file definition |
|
1575 if (fd) |
|
1576 { |
|
1577 fd->insertNamespace(nd); |
|
1578 fd->addUsingDirective(nd); |
|
1579 } |
|
1580 |
|
1581 // the empty string test is needed for extract all case |
|
1582 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1583 nd->insertUsedFile(root->fileName); |
|
1584 // add class to the list |
|
1585 Doxygen::namespaceSDict->inSort(name,nd); |
|
1586 nd->setRefItems(root->sli); |
|
1587 } |
|
1588 } |
|
1589 |
|
1590 rootNav->releaseEntry(); |
|
1591 } |
|
1592 RECURSE_ENTRYTREE(findUsingDirectives,rootNav); |
|
1593 } |
|
1594 |
|
1595 //---------------------------------------------------------------------- |
|
1596 |
|
1597 static void buildListOfUsingDecls(EntryNav *rootNav) |
|
1598 { |
|
1599 if (rootNav->section()==Entry::USINGDECL_SEC && |
|
1600 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member |
|
1601 ) |
|
1602 { |
|
1603 rootNav->loadEntry(g_storage); |
|
1604 Entry *root = rootNav->entry(); |
|
1605 |
|
1606 QCString name = substitute(root->name,".","::"); |
|
1607 if (g_usingDeclarations.find(name)==0) |
|
1608 { |
|
1609 FileDef *fd = rootNav->fileDef(); |
|
1610 if (fd) |
|
1611 { |
|
1612 g_usingDeclarations.insert(name,fd); |
|
1613 } |
|
1614 } |
|
1615 |
|
1616 rootNav->releaseEntry(); |
|
1617 } |
|
1618 RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav); |
|
1619 } |
|
1620 |
|
1621 |
|
1622 static void findUsingDeclarations(EntryNav *rootNav) |
|
1623 { |
|
1624 if (rootNav->section()==Entry::USINGDECL_SEC && |
|
1625 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member |
|
1626 ) |
|
1627 { |
|
1628 rootNav->loadEntry(g_storage); |
|
1629 Entry *root = rootNav->entry(); |
|
1630 |
|
1631 //printf("Found using declaration %s at line %d of %s inside section %x\n", |
|
1632 // root->name.data(),root->startLine,root->fileName.data(), |
|
1633 // rootNav->parent()->section()); |
|
1634 if (!root->name.isEmpty()) |
|
1635 { |
|
1636 ClassDef *usingCd = 0; |
|
1637 NamespaceDef *nd = 0; |
|
1638 FileDef *fd = rootNav->fileDef(); |
|
1639 QCString scName; |
|
1640 |
|
1641 // see if the using statement was found inside a namespace or inside |
|
1642 // the global file scope. |
|
1643 if (rootNav->parent()->section() == Entry::NAMESPACE_SEC) |
|
1644 { |
|
1645 scName=rootNav->parent()->name(); |
|
1646 if (!scName.isEmpty()) |
|
1647 { |
|
1648 nd = getResolvedNamespace(scName); |
|
1649 } |
|
1650 } |
|
1651 |
|
1652 // Assume the using statement was used to import a class. |
|
1653 // Find the scope in which the `using' namespace is defined by prepending |
|
1654 // the possible scopes in which the using statement was found, starting |
|
1655 // with the most inner scope and going to the most outer scope (i.e. |
|
1656 // file scope). |
|
1657 |
|
1658 QCString name = substitute(root->name,".","::"); //Java/C# scope->internal |
|
1659 usingCd = getClass(name); |
|
1660 if (usingCd==0) |
|
1661 { |
|
1662 usingCd = Doxygen::hiddenClasses->find(name); |
|
1663 } |
|
1664 |
|
1665 //printf("%s -> %p\n",root->name.data(),usingCd); |
|
1666 if (usingCd==0) // definition not in the input => add an artificial class |
|
1667 { |
|
1668 Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n", |
|
1669 name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1); |
|
1670 usingCd = new ClassDef( |
|
1671 "<using>",1, |
|
1672 name,ClassDef::Class); |
|
1673 Doxygen::hiddenClasses->append(root->name,usingCd); |
|
1674 usingCd->setArtificial(TRUE); |
|
1675 } |
|
1676 else |
|
1677 { |
|
1678 Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n", |
|
1679 usingCd->name().data(),nd?nd->name().data():fd->name().data()); |
|
1680 } |
|
1681 |
|
1682 if (usingCd) // add the class to the correct scope |
|
1683 { |
|
1684 if (nd) |
|
1685 { |
|
1686 //printf("Inside namespace %s\n",nd->name().data()); |
|
1687 nd->addUsingDeclaration(usingCd); |
|
1688 } |
|
1689 else if (fd) |
|
1690 { |
|
1691 //printf("Inside file %s\n",fd->name().data()); |
|
1692 fd->addUsingDeclaration(usingCd); |
|
1693 } |
|
1694 } |
|
1695 } |
|
1696 |
|
1697 rootNav->releaseEntry(); |
|
1698 } |
|
1699 RECURSE_ENTRYTREE(findUsingDeclarations,rootNav); |
|
1700 } |
|
1701 |
|
1702 //---------------------------------------------------------------------- |
|
1703 |
|
1704 static void findUsingDeclImports(EntryNav *rootNav) |
|
1705 { |
|
1706 if (rootNav->section()==Entry::USINGDECL_SEC && |
|
1707 (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member |
|
1708 ) |
|
1709 { |
|
1710 //printf("Found using declaration %s at line %d of %s inside section %x\n", |
|
1711 // root->name.data(),root->startLine,root->fileName.data(), |
|
1712 // root->parent->section); |
|
1713 QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name()); |
|
1714 fullName=stripAnonymousNamespaceScope(fullName); |
|
1715 fullName=stripTemplateSpecifiersFromScope(fullName); |
|
1716 ClassDef *cd = getClass(fullName); |
|
1717 if (cd) |
|
1718 { |
|
1719 //printf("found class %s\n",cd->name().data()); |
|
1720 int i=rootNav->name().find("::"); |
|
1721 if (i!=-1) |
|
1722 { |
|
1723 QCString scope=rootNav->name().left(i); |
|
1724 QCString memName=rootNav->name().right(rootNav->name().length()-i-2); |
|
1725 ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter |
|
1726 if (bcd) |
|
1727 { |
|
1728 //printf("found class %s\n",bcd->name().data()); |
|
1729 MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict(); |
|
1730 if (mndict) |
|
1731 { |
|
1732 MemberNameInfo *mni = mndict->find(memName); |
|
1733 if (mni) |
|
1734 { |
|
1735 MemberNameInfoIterator mnii(*mni); |
|
1736 MemberInfo *mi; |
|
1737 for ( ; (mi=mnii.current()) ; ++mnii ) |
|
1738 { |
|
1739 MemberDef *md = mi->memberDef; |
|
1740 if (md && md->protection()!=Private) |
|
1741 { |
|
1742 |
|
1743 rootNav->loadEntry(g_storage); |
|
1744 Entry *root = rootNav->entry(); |
|
1745 |
|
1746 //printf("found member %s\n",mni->memberName()); |
|
1747 MemberDef *newMd = 0; |
|
1748 { |
|
1749 LockingPtr<ArgumentList> templAl = md->templateArguments(); |
|
1750 LockingPtr<ArgumentList> al = md->templateArguments(); |
|
1751 newMd = new MemberDef( |
|
1752 root->fileName,root->startLine, |
|
1753 md->typeString(),memName,md->argsString(), |
|
1754 md->excpString(),root->protection,root->virt, |
|
1755 md->isStatic(),Member,md->memberType(), |
|
1756 templAl.pointer(),al.pointer() |
|
1757 ); |
|
1758 } |
|
1759 newMd->setMemberClass(cd); |
|
1760 cd->insertMember(newMd); |
|
1761 if (!root->doc.isEmpty() || !root->brief.isEmpty()) |
|
1762 { |
|
1763 newMd->setDocumentation(root->doc,root->docFile,root->docLine); |
|
1764 newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1765 newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
1766 } |
|
1767 else |
|
1768 { |
|
1769 newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine()); |
|
1770 newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine()); |
|
1771 newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine()); |
|
1772 } |
|
1773 newMd->setDefinition(md->definition()); |
|
1774 newMd->enableCallGraph(root->callGraph); |
|
1775 newMd->enableCallerGraph(root->callerGraph); |
|
1776 newMd->setBitfields(md->bitfieldString()); |
|
1777 newMd->addSectionsToDefinition(root->anchors); |
|
1778 newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine()); |
|
1779 newMd->setBodyDef(md->getBodyDef()); |
|
1780 newMd->setInitializer(md->initializer()); |
|
1781 newMd->setMaxInitLines(md->initializerLines()); |
|
1782 newMd->setMemberGroupId(root->mGrpId); |
|
1783 newMd->setMemberSpecifiers(md->getMemberSpecifiers()); |
|
1784 |
|
1785 rootNav->releaseEntry(); |
|
1786 } |
|
1787 } |
|
1788 } |
|
1789 } |
|
1790 } |
|
1791 } |
|
1792 } |
|
1793 |
|
1794 } |
|
1795 RECURSE_ENTRYTREE(findUsingDeclImports,rootNav); |
|
1796 } |
|
1797 |
|
1798 //---------------------------------------------------------------------- |
|
1799 |
|
1800 static void findIncludedUsingDirectives() |
|
1801 { |
|
1802 // first mark all files as not visited |
|
1803 FileNameListIterator fnli(*Doxygen::inputNameList); |
|
1804 FileName *fn; |
|
1805 for (fnli.toFirst();(fn=fnli.current());++fnli) |
|
1806 { |
|
1807 FileNameIterator fni(*fn); |
|
1808 FileDef *fd; |
|
1809 for (;(fd=fni.current());++fni) |
|
1810 { |
|
1811 fd->visited=FALSE; |
|
1812 } |
|
1813 } |
|
1814 // then recursively add using directives found in #include files |
|
1815 // to files that have not been visited. |
|
1816 for (fnli.toFirst();(fn=fnli.current());++fnli) |
|
1817 { |
|
1818 FileNameIterator fni(*fn); |
|
1819 FileDef *fd; |
|
1820 for (fni.toFirst();(fd=fni.current());++fni) |
|
1821 { |
|
1822 if (!fd->visited) |
|
1823 { |
|
1824 //printf("----- adding using directives for file %s\n",fd->name().data()); |
|
1825 fd->addIncludedUsingDirectives(); |
|
1826 } |
|
1827 } |
|
1828 } |
|
1829 } |
|
1830 |
|
1831 //---------------------------------------------------------------------- |
|
1832 |
|
1833 static MemberDef *addVariableToClass( |
|
1834 EntryNav *rootNav, |
|
1835 ClassDef *cd, |
|
1836 MemberDef::MemberType mtype, |
|
1837 const QCString &name, |
|
1838 bool fromAnnScope, |
|
1839 MemberDef *fromAnnMemb, |
|
1840 Protection prot, |
|
1841 Relationship related) |
|
1842 { |
|
1843 Entry *root = rootNav->entry(); |
|
1844 |
|
1845 QCString qualScope = cd->qualifiedNameWithTemplateParameters(); |
|
1846 QCString scopeSeparator="::"; |
|
1847 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA")) |
|
1848 { |
|
1849 qualScope = substitute(qualScope,"::","."); |
|
1850 scopeSeparator="."; |
|
1851 } |
|
1852 Debug::print(Debug::Variables,0, |
|
1853 " class variable:\n" |
|
1854 " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n", |
|
1855 root->type.data(), |
|
1856 qualScope.data(), |
|
1857 name.data(), |
|
1858 root->args.data(), |
|
1859 root->protection, |
|
1860 fromAnnScope, |
|
1861 root->initializer.data() |
|
1862 ); |
|
1863 |
|
1864 QCString def; |
|
1865 if (!root->type.isEmpty()) |
|
1866 { |
|
1867 if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES")) |
|
1868 { |
|
1869 def=root->type+" "+name+root->args; |
|
1870 } |
|
1871 else |
|
1872 { |
|
1873 def=root->type+" "+qualScope+scopeSeparator+name+root->args; |
|
1874 } |
|
1875 } |
|
1876 else |
|
1877 { |
|
1878 if (Config_getBool("HIDE_SCOPE_NAMES")) |
|
1879 { |
|
1880 def=name+root->args; |
|
1881 } |
|
1882 else |
|
1883 { |
|
1884 def=qualScope+scopeSeparator+name+root->args; |
|
1885 } |
|
1886 } |
|
1887 def.stripPrefix("static "); |
|
1888 |
|
1889 // see if the member is already found in the same scope |
|
1890 // (this may be the case for a static member that is initialized |
|
1891 // outside the class) |
|
1892 MemberName *mn=Doxygen::memberNameSDict->find(name); |
|
1893 if (mn) |
|
1894 { |
|
1895 MemberNameIterator mni(*mn); |
|
1896 MemberDef *md; |
|
1897 for (mni.toFirst();(md=mni.current());++mni) |
|
1898 { |
|
1899 //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n", |
|
1900 // md->getClassDef(),cd,root->type.data(),md->typeString()); |
|
1901 if (md->getClassDef()==cd && |
|
1902 removeRedundantWhiteSpace(root->type)==md->typeString()) |
|
1903 // member already in the scope |
|
1904 { |
|
1905 |
|
1906 if (root->objc && |
|
1907 root->mtype==Property && |
|
1908 md->memberType()==MemberDef::Variable) |
|
1909 { // Objective-C 2.0 property |
|
1910 // turn variable into a property |
|
1911 md->setProtection(root->protection); |
|
1912 cd->reclassifyMember(md,MemberDef::Property); |
|
1913 } |
|
1914 addMemberDocs(rootNav,md,def,0,FALSE); |
|
1915 //printf(" Member already found!\n"); |
|
1916 return md; |
|
1917 } |
|
1918 } |
|
1919 } |
|
1920 |
|
1921 // new member variable, typedef or enum value |
|
1922 MemberDef *md=new MemberDef( |
|
1923 root->fileName,root->startLine, |
|
1924 root->type,name,root->args,0, |
|
1925 prot,Normal,root->stat,related, |
|
1926 mtype,0,0); |
|
1927 md->setTagInfo(rootNav->tagInfo()); |
|
1928 md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope()) |
|
1929 //md->setDefFile(root->fileName); |
|
1930 //md->setDefLine(root->startLine); |
|
1931 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
1932 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
1933 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
1934 md->setDefinition(def); |
|
1935 md->setBitfields(root->bitfields); |
|
1936 md->addSectionsToDefinition(root->anchors); |
|
1937 md->setFromAnonymousScope(fromAnnScope); |
|
1938 md->setFromAnonymousMember(fromAnnMemb); |
|
1939 //md->setIndentDepth(indentDepth); |
|
1940 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
1941 md->setInitializer(root->initializer); |
|
1942 md->setMaxInitLines(root->initLines); |
|
1943 md->setMemberGroupId(root->mGrpId); |
|
1944 md->setMemberSpecifiers(root->spec); |
|
1945 md->setReadAccessor(root->read); |
|
1946 md->setWriteAccessor(root->write); |
|
1947 md->enableCallGraph(root->callGraph); |
|
1948 md->enableCallerGraph(root->callerGraph); |
|
1949 md->setHidden(root->hidden); |
|
1950 md->setArtificial(root->artificial); |
|
1951 addMemberToGroups(root,md); |
|
1952 //if (root->mGrpId!=-1) |
|
1953 //{ |
|
1954 // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId); |
|
1955 // md->setMemberGroup(memberGroupDict[root->mGrpId]); |
|
1956 // |
|
1957 md->setBodyDef(rootNav->fileDef()); |
|
1958 |
|
1959 //printf(" Adding member=%s\n",md->name().data()); |
|
1960 // add the member to the global list |
|
1961 if (mn) |
|
1962 { |
|
1963 mn->append(md); |
|
1964 } |
|
1965 else // new variable name |
|
1966 { |
|
1967 mn = new MemberName(name); |
|
1968 mn->append(md); |
|
1969 //printf("Adding memberName=%s\n",mn->memberName()); |
|
1970 //Doxygen::memberNameDict.insert(name,mn); |
|
1971 //Doxygen::memberNameList.append(mn); |
|
1972 Doxygen::memberNameSDict->append(name,mn); |
|
1973 // add the member to the class |
|
1974 } |
|
1975 //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd); |
|
1976 cd->insertMember(md); |
|
1977 md->setRefItems(root->sli); |
|
1978 |
|
1979 //TODO: insert FileDef instead of filename strings. |
|
1980 cd->insertUsedFile(root->fileName); |
|
1981 rootNav->changeSection(Entry::EMPTY_SEC); |
|
1982 return md; |
|
1983 } |
|
1984 |
|
1985 //---------------------------------------------------------------------- |
|
1986 /** Recursively dumps the include files.*/ |
|
1987 void dumpIncludeGraphRecursive(const FileDef *fd, const QCString &prefix) |
|
1988 { |
|
1989 if (fd && fd->includeFileList()) { |
|
1990 QList<IncludeInfo> *incList = fd->includeFileList(); |
|
1991 IncludeInfo *ii; |
|
1992 for (ii=incList->first(); ii != 0; ii=incList->next()) { |
|
1993 FileDef *incFd = ii->fileDef; |
|
1994 if (incFd) { |
|
1995 Debug::print(Debug::IncludeGraph, 0, "%sInc: %s\n", prefix.data(), incFd->absFilePath().data()); |
|
1996 dumpIncludeGraphRecursive(incFd, " "+prefix); |
|
1997 } |
|
1998 } |
|
1999 } |
|
2000 } |
|
2001 |
|
2002 /** Dumps the include files.*/ |
|
2003 void dumpIncludeGraph() |
|
2004 { |
|
2005 if (Debug::isFlagSet(Debug::IncludeGraph)) { |
|
2006 Debug::print(Debug::IncludeGraph, 0, "Include Graph:\n"); |
|
2007 FileNameListIterator incFnli(*Doxygen::inputNameList); |
|
2008 FileName *incFnLoop; |
|
2009 for (;(incFnLoop=incFnli.current()); ++incFnli) { |
|
2010 FileNameIterator incFni(*incFnLoop); |
|
2011 FileDef *fd; |
|
2012 for (;(fd=incFni.current()); ++incFni) { |
|
2013 Debug::print(Debug::IncludeGraph, 0, "File: %s\n", fd->absFilePath().data()); |
|
2014 dumpIncludeGraphRecursive(fd, " "); |
|
2015 } |
|
2016 } |
|
2017 } |
|
2018 } |
|
2019 |
|
2020 /** Recursively searches the supplied FileDef for an filename that |
|
2021 matches the rootFileName and returns the FileDef* of the include file or |
|
2022 0 on failure. |
|
2023 @param fd The FileDef to search. |
|
2024 @param rootFileName The filename to match on. |
|
2025 */ |
|
2026 static FileDef* findIncludeMatch(const FileDef *fd, const QCString &rootFileName) |
|
2027 { |
|
2028 if (fd && fd->includeFileList()) { |
|
2029 // Search the include dependency list for a file that matches root->fileName |
|
2030 QList<IncludeInfo> *incList = fd->includeFileList(); |
|
2031 IncludeInfo *ii; |
|
2032 for (ii=incList->first(); ii != 0; ii=incList->next()) { |
|
2033 FileDef *incFd = ii->fileDef; |
|
2034 // NOTE: this test stops only direct recursion, not indirect recursion |
|
2035 if (incFd && incFd != fd) { |
|
2036 if (incFd->absFilePath() == rootFileName) { |
|
2037 return incFd; |
|
2038 } else { |
|
2039 // Depth first search |
|
2040 FileDef *recurseFd = findIncludeMatch(incFd, rootFileName); |
|
2041 if (recurseFd) { |
|
2042 return recurseFd; |
|
2043 } |
|
2044 } |
|
2045 } |
|
2046 } |
|
2047 } |
|
2048 return 0; |
|
2049 } |
|
2050 |
|
2051 /** Adds an include file represented by fd to the list of input files |
|
2052 add it to the Doxygen::inputNameList so that the back ends can see it |
|
2053 as 'forced include'. |
|
2054 @param fd The FileDef that describes the file to include. |
|
2055 */ |
|
2056 static void addIncludeFileToInput(FileDef *fd) |
|
2057 { |
|
2058 FileNameListIterator incFnli(*Doxygen::inputNameList); |
|
2059 FileName *incFnLoop; |
|
2060 for (;(incFnLoop=incFnli.current()); ++incFnli) { |
|
2061 FileNameIterator incFni(*incFnLoop); |
|
2062 FileDef *listFd; |
|
2063 for (;(listFd=incFni.current()); ++incFni) { |
|
2064 // TODO: Test for file name not FileDef address |
|
2065 if (listFd == fd) { |
|
2066 // Already have it |
|
2067 return; |
|
2068 } |
|
2069 } |
|
2070 } |
|
2071 //printf("Forcing include file onto inputNameList: %s\n", incFd->absFilePath().data()); |
|
2072 //FileName *fn = Doxygen::inputNameList->first(); |
|
2073 FileNameList *fnList = Doxygen::inputNameList; |
|
2074 FileName *incFn = new FileName(fd->absFilePath(), fd->name()); |
|
2075 incFn->append(fd); |
|
2076 fnList->inSort(incFn); |
|
2077 //printf("Forced include file pushed onto inputNameList %p: %s\n", fnList, fd->absFilePath().data()); |
|
2078 } |
|
2079 |
|
2080 static MemberDef *addVariableToFile( |
|
2081 EntryNav *rootNav, |
|
2082 MemberDef::MemberType mtype, |
|
2083 const QCString &scope, |
|
2084 const QCString &name, |
|
2085 bool fromAnnScope, |
|
2086 /*int indentDepth,*/ |
|
2087 MemberDef *fromAnnMemb) |
|
2088 { |
|
2089 Entry *root = rootNav->entry(); |
|
2090 Debug::print(Debug::Variables,0, |
|
2091 " global variable:\n" |
|
2092 " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d\n", |
|
2093 root->type.data(), |
|
2094 scope.data(), |
|
2095 name.data(), |
|
2096 root->args.data(), |
|
2097 root->protection, |
|
2098 mtype |
|
2099 ); |
|
2100 |
|
2101 FileDef *fd = rootNav->fileDef(); |
|
2102 |
|
2103 // see if we have a typedef that should hide a struct or union |
|
2104 if (mtype==MemberDef::Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT")) |
|
2105 { |
|
2106 QCString type = root->type; |
|
2107 type.stripPrefix("typedef "); |
|
2108 if (type.left(7)=="struct " || type.left(6)=="union ") |
|
2109 { |
|
2110 type.stripPrefix("struct "); |
|
2111 type.stripPrefix("union "); |
|
2112 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*"); |
|
2113 int l,s; |
|
2114 s = re.match(type,0,&l); |
|
2115 if (s>=0) |
|
2116 { |
|
2117 QCString typeValue = type.mid(s,l); |
|
2118 ClassDef *cd = getClass(typeValue); |
|
2119 if (cd) |
|
2120 { |
|
2121 // this typedef should hide compound name cd, so we |
|
2122 // change the name that is displayed from cd. |
|
2123 cd->setClassName(name); |
|
2124 cd->setDocumentation(root->doc,root->docFile,root->docLine); |
|
2125 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
2126 return 0; |
|
2127 } |
|
2128 } |
|
2129 } |
|
2130 } |
|
2131 |
|
2132 // see if the function is inside a namespace |
|
2133 NamespaceDef *nd = 0; |
|
2134 QCString nscope; |
|
2135 if (!scope.isEmpty()) |
|
2136 { |
|
2137 if (scope.find('@')!=-1) return 0; // anonymous scope! |
|
2138 //nscope=removeAnonymousScopes(scope); |
|
2139 //if (!nscope.isEmpty()) |
|
2140 //{ |
|
2141 nd = getResolvedNamespace(scope); |
|
2142 //} |
|
2143 } |
|
2144 QCString def; |
|
2145 |
|
2146 // determine the definition of the global variable |
|
2147 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && |
|
2148 !Config_getBool("HIDE_SCOPE_NAMES") |
|
2149 ) |
|
2150 // variable is inside a namespace, so put the scope before the name |
|
2151 { |
|
2152 static bool optimizeForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA"); |
|
2153 QCString sep="::"; |
|
2154 if (optimizeForJava) sep="."; |
|
2155 |
|
2156 if (!root->type.isEmpty()) |
|
2157 { |
|
2158 def=root->type+" "+nd->name()+sep+name+root->args; |
|
2159 } |
|
2160 else |
|
2161 { |
|
2162 def=nd->name()+sep+name+root->args; |
|
2163 } |
|
2164 } |
|
2165 else |
|
2166 { |
|
2167 if (!root->type.isEmpty() && !root->name.isEmpty()) |
|
2168 { |
|
2169 if (name.at(0)=='@') // dummy variable representing annonymous union |
|
2170 def=root->type; |
|
2171 else |
|
2172 def=root->type+" "+name+root->args; |
|
2173 } |
|
2174 else |
|
2175 { |
|
2176 def=name+root->args; |
|
2177 } |
|
2178 } |
|
2179 def.stripPrefix("static "); |
|
2180 |
|
2181 MemberName *mn=Doxygen::functionNameSDict->find(name); |
|
2182 if (mn) |
|
2183 { |
|
2184 //QCString nscope=removeAnonymousScopes(scope); |
|
2185 //NamespaceDef *nd=0; |
|
2186 //if (!nscope.isEmpty()) |
|
2187 if (!scope.isEmpty()) |
|
2188 { |
|
2189 nd = getResolvedNamespace(scope); |
|
2190 } |
|
2191 MemberNameIterator mni(*mn); |
|
2192 MemberDef *md; |
|
2193 for (mni.toFirst();(md=mni.current());++mni) |
|
2194 { |
|
2195 if ( |
|
2196 ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && |
|
2197 root->fileName==md->getFileDef()->absFilePath() |
|
2198 ) // both variable names in the same file |
|
2199 || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace |
|
2200 ) |
|
2201 && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables |
|
2202 && !md->isEnumerate() // in C# an enum value and enum can have the same name |
|
2203 ) |
|
2204 // variable already in the scope |
|
2205 { |
|
2206 if (md->getFileDef() && |
|
2207 ! // not a php array |
|
2208 ( |
|
2209 (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) && |
|
2210 (md->argsString()!=root->args && root->args.find('[')!=-1) |
|
2211 ) |
|
2212 ) |
|
2213 // not a php array variable |
|
2214 { |
|
2215 |
|
2216 Debug::print(Debug::Variables,0, |
|
2217 " variable already found: scope=%s\n",md->getOuterScope()->name().data()); |
|
2218 addMemberDocs(rootNav,md,def,0,FALSE); |
|
2219 md->setRefItems(root->sli); |
|
2220 return md; |
|
2221 } |
|
2222 } |
|
2223 } |
|
2224 } |
|
2225 Debug::print(Debug::Variables,0, |
|
2226 " new variable, nd=%s!\n",nd?nd->name().data():"<global>"); |
|
2227 // new global variable, enum value or typedef |
|
2228 MemberDef *md=new MemberDef( |
|
2229 root->fileName,root->startLine, |
|
2230 root->type,name,root->args,0, |
|
2231 Public, Normal,root->stat,Member, |
|
2232 mtype,0,0); |
|
2233 md->setTagInfo(rootNav->tagInfo()); |
|
2234 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
2235 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
2236 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
2237 md->addSectionsToDefinition(root->anchors); |
|
2238 md->setFromAnonymousScope(fromAnnScope); |
|
2239 md->setFromAnonymousMember(fromAnnMemb); |
|
2240 md->setInitializer(root->initializer); |
|
2241 md->setMaxInitLines(root->initLines); |
|
2242 md->setMemberGroupId(root->mGrpId); |
|
2243 md->setDefinition(def); |
|
2244 md->enableCallGraph(root->callGraph); |
|
2245 md->enableCallerGraph(root->callerGraph); |
|
2246 md->setExplicitExternal(root->explicitExternal); |
|
2247 //md->setOuterScope(fd); |
|
2248 if (!root->explicitExternal) |
|
2249 { |
|
2250 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
2251 md->setBodyDef(fd); |
|
2252 } |
|
2253 addMemberToGroups(root,md); |
|
2254 |
|
2255 md->setRefItems(root->sli); |
|
2256 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') |
|
2257 { |
|
2258 md->setNamespace(nd); |
|
2259 nd->insertMember(md); |
|
2260 } |
|
2261 |
|
2262 // add member to the file (we do this even if we have already inserted |
|
2263 // it into the namespace. |
|
2264 if (fd) |
|
2265 { |
|
2266 //printf("Setting FileDef %s\n", fd->fileName().data()); |
|
2267 if (root->fileName != fd->absFilePath()) { |
|
2268 //printf("addVariableToFile() Missmatch Name=\"%s\" Root=%s, FileDef=%s\n", |
|
2269 // name.data(), |
|
2270 // root->fileName.data(), |
|
2271 // fd->absFilePath().data() |
|
2272 // ); |
|
2273 // Now search the include dependency list for a file that matches root->fileName |
|
2274 FileDef *incFd = findIncludeMatch(fd, root->fileName); |
|
2275 if (incFd) { |
|
2276 //printf("Found include file match on: %s\n", incFd->absFilePath().data()); |
|
2277 // If found add this FileDef* to the member and add the MemberDef* to the FileDef |
|
2278 md->setFileDef(incFd); |
|
2279 incFd->insertMember(md); |
|
2280 md->setBodyDef(incFd); |
|
2281 // If this FileDef is not in Doxygen::inputNameList and |
|
2282 // Config_getBool("OUTPUT_INCLUDES") is true then |
|
2283 // add it to the Doxygen::inputNameList so that the back ends |
|
2284 // can see it as 'forced include'. |
|
2285 if (Config_getBool("OUTPUT_INCLUDES")) { |
|
2286 addIncludeFileToInput(incFd); |
|
2287 } |
|
2288 } else { |
|
2289 printf("Warning: addVariableToFile() failed to resolve missmatch Name=\"%s\" Root=%s, FileDef=%s\n", |
|
2290 name.data(), |
|
2291 root->fileName.data(), |
|
2292 fd->absFilePath().data() |
|
2293 ); |
|
2294 //md->setFileDef(fd); |
|
2295 //fd->insertMember(md); |
|
2296 } |
|
2297 } else { |
|
2298 //printf("addVariableToFile() Match OK FileDef=%s\n", fd->absFilePath().data()); |
|
2299 md->setFileDef(fd); |
|
2300 fd->insertMember(md); |
|
2301 } |
|
2302 } |
|
2303 |
|
2304 // add member definition to the list of globals |
|
2305 if (mn) |
|
2306 { |
|
2307 mn->append(md); |
|
2308 } |
|
2309 else |
|
2310 { |
|
2311 mn = new MemberName(name); |
|
2312 mn->append(md); |
|
2313 // PaulRoss: This first line looks wrong to me but links to typedef's don't work without it! |
|
2314 Doxygen::functionNameSDict->append(name,mn); |
|
2315 //Doxygen::memberNameSDict->append(name,mn); |
|
2316 } |
|
2317 rootNav->changeSection(Entry::EMPTY_SEC); |
|
2318 return md; |
|
2319 } |
|
2320 |
|
2321 /*! See if the return type string \a type is that of a function pointer |
|
2322 * \returns -1 if this is not a function pointer variable or |
|
2323 * the index at which the brace of (...*name) was found. |
|
2324 */ |
|
2325 static int findFunctionPtr(const QCString &type,int *pLength=0) |
|
2326 { |
|
2327 static const QRegExp re("([^)]*\\*[^)]*)"); |
|
2328 int i=-1,l; |
|
2329 if (!type.isEmpty() && // return type is non-empty |
|
2330 (i=re.match(type,0,&l))!=-1 && // contains (...*...) |
|
2331 type.find("operator")==-1 && // not an operator |
|
2332 (type.find(")(")==-1 || type.find("typedef ")!=-1) |
|
2333 // not a function pointer return type |
|
2334 ) |
|
2335 { |
|
2336 if (pLength) *pLength=l; |
|
2337 return i; |
|
2338 } |
|
2339 else |
|
2340 { |
|
2341 return -1; |
|
2342 } |
|
2343 } |
|
2344 |
|
2345 |
|
2346 /*! Returns TRUE iff \a type is a class within scope \a context. |
|
2347 * Used to detect variable declarations that look like function prototypes. |
|
2348 */ |
|
2349 static bool isVarWithConstructor(EntryNav *rootNav) |
|
2350 { |
|
2351 static QRegExp initChars("[0-9\"'&*!^]+"); |
|
2352 static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*"); |
|
2353 bool result=FALSE; |
|
2354 bool typeIsClass; |
|
2355 QCString type; |
|
2356 Definition *ctx = 0; |
|
2357 FileDef *fd = 0; |
|
2358 int ti; |
|
2359 |
|
2360 //printf("isVarWithConstructor(%s)\n",rootNav->name().data()); |
|
2361 rootNav->loadEntry(g_storage); |
|
2362 Entry *root = rootNav->entry(); |
|
2363 |
|
2364 if (rootNav->parent()->section() & Entry::COMPOUND_MASK) |
|
2365 { // inside a class |
|
2366 result=FALSE; |
|
2367 goto done; |
|
2368 } |
|
2369 else if ((fd = rootNav->fileDef()) && |
|
2370 (fd->name().right(2)==".c" || fd->name().right(2)==".h") |
|
2371 ) |
|
2372 { // inside a .c file |
|
2373 result=FALSE; |
|
2374 goto done; |
|
2375 } |
|
2376 if (root->type.isEmpty()) |
|
2377 { |
|
2378 result=FALSE; |
|
2379 goto done; |
|
2380 } |
|
2381 if (!rootNav->parent()->name().isEmpty()) |
|
2382 { |
|
2383 ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name()); |
|
2384 } |
|
2385 type = root->type; |
|
2386 // remove qualifiers |
|
2387 findAndRemoveWord(type,"const"); |
|
2388 findAndRemoveWord(type,"static"); |
|
2389 findAndRemoveWord(type,"volatile"); |
|
2390 //if (type.left(6)=="const ") type=type.right(type.length()-6); |
|
2391 typeIsClass=getResolvedClass(ctx,fd,type)!=0; |
|
2392 if (!typeIsClass && (ti=type.find('<'))!=-1) |
|
2393 { |
|
2394 typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0; |
|
2395 } |
|
2396 if (typeIsClass) // now we still have to check if the arguments are |
|
2397 // types or values. Since we do not have complete type info |
|
2398 // we need to rely on heuristics :-( |
|
2399 { |
|
2400 //printf("typeIsClass\n"); |
|
2401 ArgumentList *al = root->argList; |
|
2402 if (al==0 || al->isEmpty()) |
|
2403 { |
|
2404 result=FALSE; // empty arg list -> function prototype. |
|
2405 goto done; |
|
2406 } |
|
2407 ArgumentListIterator ali(*al); |
|
2408 Argument *a; |
|
2409 for (ali.toFirst();(a=ali.current());++ali) |
|
2410 { |
|
2411 if (!a->name.isEmpty() || !a->defval.isEmpty()) |
|
2412 { |
|
2413 if (a->name.find(initChars)==0) |
|
2414 { |
|
2415 result=TRUE; |
|
2416 } |
|
2417 else |
|
2418 { |
|
2419 result=FALSE; // arg has (type,name) pair -> function prototype |
|
2420 } |
|
2421 goto done; |
|
2422 } |
|
2423 if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) |
|
2424 { |
|
2425 result=FALSE; // arg type is a known type |
|
2426 goto done; |
|
2427 } |
|
2428 if (checkIfTypedef(ctx,fd,a->type)) |
|
2429 { |
|
2430 //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__); |
|
2431 result=FALSE; // argument is a typedef |
|
2432 goto done; |
|
2433 } |
|
2434 if (a->type.at(a->type.length()-1)=='*' || |
|
2435 a->type.at(a->type.length()-1)=='&') |
|
2436 // type ends with * or & => pointer or reference |
|
2437 { |
|
2438 result=FALSE; |
|
2439 goto done; |
|
2440 } |
|
2441 if (a->type.find(initChars)==0) |
|
2442 { |
|
2443 result=TRUE; // argument type starts with typical initializer char |
|
2444 goto done; |
|
2445 } |
|
2446 QCString resType=resolveTypeDef(ctx,a->type); |
|
2447 if (resType.isEmpty()) resType=a->type; |
|
2448 int len; |
|
2449 if (idChars.match(resType,0,&len)==0) // resType starts with identifier |
|
2450 { |
|
2451 resType=resType.left(len); |
|
2452 //printf("resType=%s\n",resType.data()); |
|
2453 if (resType=="int" || resType=="long" || resType=="float" || |
|
2454 resType=="double" || resType=="char" || resType=="signed" || |
|
2455 resType=="const" || resType=="unsigned" || resType=="void") |
|
2456 { |
|
2457 result=FALSE; // type keyword -> function prototype |
|
2458 goto done; |
|
2459 } |
|
2460 } |
|
2461 } |
|
2462 result=TRUE; |
|
2463 } |
|
2464 |
|
2465 done: |
|
2466 //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(), |
|
2467 // root->type.data(),result); |
|
2468 rootNav->releaseEntry(); |
|
2469 return result; |
|
2470 } |
|
2471 |
|
2472 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1) |
|
2473 { |
|
2474 rootNav->loadEntry(g_storage); |
|
2475 Entry *root = rootNav->entry(); |
|
2476 |
|
2477 Debug::print(Debug::Variables,0, |
|
2478 "VARIABLE_SEC: \n" |
|
2479 " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d\n", |
|
2480 root->type.data(), |
|
2481 root->name.data(), |
|
2482 root->args.data(), |
|
2483 root->bodyLine, |
|
2484 root->mGrpId |
|
2485 ); |
|
2486 //Entry *pParent = root->parent(); |
|
2487 //if (pParent) { |
|
2488 // printf("root->parent->name=%s\n",root->parent()->name.data()); |
|
2489 //} else { |
|
2490 // printf("NO Parent\n"); |
|
2491 //} |
|
2492 if (root->type.isEmpty() && root->name.find("operator")==-1 && |
|
2493 (root->name.find('*')!=-1 || root->name.find('&')!=-1)) |
|
2494 { |
|
2495 // recover from parse error caused by redundant braces |
|
2496 // like in "int *(var[10]);", which is parsed as |
|
2497 // type="" name="int *" args="(var[10])" |
|
2498 |
|
2499 root->type=root->name; |
|
2500 static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*"); |
|
2501 int l; |
|
2502 int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l); |
|
2503 root->name=root->args.mid(i,l); |
|
2504 root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l); |
|
2505 //printf("new: type=`%s' name=`%s' args=`%s'\n", |
|
2506 // root->type.data(),root->name.data(),root->args.data()); |
|
2507 } |
|
2508 else |
|
2509 { |
|
2510 int i=isFuncPtr; |
|
2511 if (i==-1) i=findFunctionPtr(root->type); // for typedefs isFuncPtr is not yet set |
|
2512 if (i!=-1) // function pointer |
|
2513 { |
|
2514 int ai = root->type.find('[',i); |
|
2515 if (ai>i) // function pointer array |
|
2516 { |
|
2517 root->args.prepend(root->type.right(root->type.length()-ai)); |
|
2518 root->type=root->type.left(ai); |
|
2519 } |
|
2520 else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]" |
|
2521 { |
|
2522 root->type=root->type.left(root->type.length()-1); |
|
2523 root->args.prepend(")"); |
|
2524 //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data()); |
|
2525 } |
|
2526 } |
|
2527 else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int) |
|
2528 { |
|
2529 root->type=root->type.left(root->type.length()-1); |
|
2530 root->args.prepend(")"); |
|
2531 } |
|
2532 } |
|
2533 |
|
2534 QCString scope,name=removeRedundantWhiteSpace(root->name); |
|
2535 |
|
2536 // find the scope of this variable |
|
2537 EntryNav *p = rootNav->parent(); |
|
2538 while ((p->section() & Entry::SCOPE_MASK)) |
|
2539 { |
|
2540 QCString scopeName = p->name(); |
|
2541 if (!scopeName.isEmpty()) |
|
2542 { |
|
2543 scope.prepend(scopeName); |
|
2544 break; |
|
2545 } |
|
2546 p=p->parent(); |
|
2547 } |
|
2548 |
|
2549 MemberDef::MemberType mtype; |
|
2550 QCString type=root->type.stripWhiteSpace(); |
|
2551 ClassDef *cd=0; |
|
2552 bool isRelated=FALSE; |
|
2553 bool isMemberOf=FALSE; |
|
2554 |
|
2555 QCString classScope=stripAnonymousNamespaceScope(scope); |
|
2556 classScope=stripTemplateSpecifiersFromScope(classScope,FALSE); |
|
2557 QCString annScopePrefix=scope.left(scope.length()-classScope.length()); |
|
2558 |
|
2559 if (root->name.findRev("::")!=-1) |
|
2560 { |
|
2561 if (root->type=="friend class" || root->type=="friend struct" || |
|
2562 root->type=="friend union") |
|
2563 { |
|
2564 cd=getClass(scope); |
|
2565 if (cd) |
|
2566 { |
|
2567 addVariableToClass(rootNav, // entry |
|
2568 cd, // class to add member to |
|
2569 MemberDef::Friend, // type of member |
|
2570 name, // name of the member |
|
2571 FALSE, // from Anonymous scope |
|
2572 0, // anonymous member |
|
2573 Public, // protection |
|
2574 Member // related to a class |
|
2575 ); |
|
2576 } |
|
2577 } |
|
2578 goto nextMember; |
|
2579 /* skip this member, because it is a |
|
2580 * static variable definition (always?), which will be |
|
2581 * found in a class scope as well, but then we know the |
|
2582 * correct protection level, so only then it will be |
|
2583 * inserted in the correct list! |
|
2584 */ |
|
2585 } |
|
2586 |
|
2587 if (type=="@") |
|
2588 mtype=MemberDef::EnumValue; |
|
2589 else if (type.left(8)=="typedef ") |
|
2590 mtype=MemberDef::Typedef; |
|
2591 else if (type.left(7)=="friend ") |
|
2592 mtype=MemberDef::Friend; |
|
2593 else if (root->mtype==Property) |
|
2594 mtype=MemberDef::Property; |
|
2595 else if (root->mtype==Event) |
|
2596 mtype=MemberDef::Event; |
|
2597 else |
|
2598 mtype=MemberDef::Variable; |
|
2599 |
|
2600 if (!root->relates.isEmpty()) // related variable |
|
2601 { |
|
2602 isRelated=TRUE; |
|
2603 isMemberOf=(root->relatesType == MemberOf); |
|
2604 if (getClass(root->relates)==0 && !scope.isEmpty()) |
|
2605 scope=mergeScopes(scope,root->relates); |
|
2606 else |
|
2607 scope=root->relates; |
|
2608 } |
|
2609 |
|
2610 cd=getClass(scope); |
|
2611 if (cd==0 && classScope!=scope) cd=getClass(classScope); |
|
2612 if (cd) |
|
2613 { |
|
2614 MemberDef *md=0; |
|
2615 |
|
2616 // if cd is an annonymous scope we insert the member |
|
2617 // into a non-annonymous scope as well. This is needed to |
|
2618 // be able to refer to it using \var or \fn |
|
2619 |
|
2620 //int indentDepth=0; |
|
2621 int si=scope.find('@'); |
|
2622 //int anonyScopes = 0; |
|
2623 bool added=FALSE; |
|
2624 |
|
2625 if (si!=-1) // anonymous scope |
|
2626 { |
|
2627 QCString pScope; |
|
2628 ClassDef *pcd=0; |
|
2629 pScope = scope.left(QMAX(si-2,0)); |
|
2630 if (!pScope.isEmpty()) |
|
2631 pScope.prepend(annScopePrefix); |
|
2632 else if (annScopePrefix.length()>2) |
|
2633 pScope=annScopePrefix.left(annScopePrefix.length()-2); |
|
2634 if (name.at(0)!='@') |
|
2635 { |
|
2636 if (!pScope.isEmpty() && (pcd=getClass(pScope))) |
|
2637 { |
|
2638 md=addVariableToClass(rootNav, // entry |
|
2639 pcd, // class to add member to |
|
2640 mtype, // member type |
|
2641 name, // member name |
|
2642 TRUE, // from anonymous scope |
|
2643 0, // from anonymous member |
|
2644 root->protection, |
|
2645 isMemberOf ? Foreign : isRelated ? Related : Member |
|
2646 ); |
|
2647 added=TRUE; |
|
2648 } |
|
2649 else // anonymous scope inside namespace or file => put variable in the global scope |
|
2650 { |
|
2651 if (mtype==MemberDef::Variable) |
|
2652 { |
|
2653 md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); |
|
2654 } |
|
2655 added=TRUE; |
|
2656 } |
|
2657 } |
|
2658 } |
|
2659 |
|
2660 //printf("name=`%s' scope=%s scope.right=%s\n", |
|
2661 // name.data(),scope.data(), |
|
2662 // scope.right(scope.length()-si).data()); |
|
2663 addVariableToClass(rootNav, // entry |
|
2664 cd, // class to add member to |
|
2665 mtype, // member type |
|
2666 name, // name of the member |
|
2667 FALSE, // from anonymous scope |
|
2668 md, // from anonymous member |
|
2669 root->protection, |
|
2670 isMemberOf ? Foreign : isRelated ? Related : Member); |
|
2671 } |
|
2672 else if (!name.isEmpty()) // global variable |
|
2673 { |
|
2674 //printf("Inserting member in global scope %s!\n",scope.data()); |
|
2675 addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0); |
|
2676 } |
|
2677 |
|
2678 nextMember: |
|
2679 rootNav->releaseEntry(); |
|
2680 } |
|
2681 |
|
2682 //---------------------------------------------------------------------- |
|
2683 // Searches the Entry tree for typedef documentation sections. |
|
2684 // If found they are stored in their class or in the global list. |
|
2685 static void buildTypedefList(EntryNav *rootNav) |
|
2686 { |
|
2687 //printf("buildVarList(%s)\n",rootNav->name().data()); |
|
2688 if (!rootNav->name().isEmpty() && |
|
2689 rootNav->section()==Entry::VARIABLE_SEC && |
|
2690 rootNav->type().find("typedef ")!=-1 // its a typedef |
|
2691 ) |
|
2692 { |
|
2693 addVariable(rootNav); |
|
2694 //printf("addVariable() done\n"); |
|
2695 } |
|
2696 if (rootNav->children()) |
|
2697 { |
|
2698 EntryNavListIterator eli(*rootNav->children()); |
|
2699 EntryNav *e; |
|
2700 for (;(e=eli.current());++eli) |
|
2701 { |
|
2702 if (e->section()!=Entry::ENUM_SEC) |
|
2703 { |
|
2704 buildTypedefList(e); |
|
2705 } |
|
2706 } |
|
2707 } |
|
2708 } |
|
2709 |
|
2710 //---------------------------------------------------------------------- |
|
2711 // Searches the Entry tree for Variable documentation sections. |
|
2712 // If found they are stored in their class or in the global list. |
|
2713 |
|
2714 static void buildVarList(EntryNav *rootNav) |
|
2715 { |
|
2716 //printf("buildVarList(%s)\n",rootNav->name().data()); |
|
2717 int isFuncPtr=-1; |
|
2718 if (!rootNav->name().isEmpty() && |
|
2719 (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) && |
|
2720 ( |
|
2721 (rootNav->section()==Entry::VARIABLE_SEC // it's a variable |
|
2722 ) || |
|
2723 (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable |
|
2724 (isFuncPtr=findFunctionPtr(rootNav->type()))!=-1 |
|
2725 ) || |
|
2726 (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor |
|
2727 isVarWithConstructor(rootNav) |
|
2728 ) |
|
2729 ) |
|
2730 ) // documented variable |
|
2731 { |
|
2732 addVariable(rootNav,isFuncPtr); |
|
2733 } |
|
2734 if (rootNav->children()) |
|
2735 { |
|
2736 EntryNavListIterator eli(*rootNav->children()); |
|
2737 EntryNav *e; |
|
2738 for (;(e=eli.current());++eli) |
|
2739 { |
|
2740 if (e->section()!=Entry::ENUM_SEC) |
|
2741 { |
|
2742 buildVarList(e); |
|
2743 } |
|
2744 } |
|
2745 } |
|
2746 } |
|
2747 |
|
2748 //---------------------------------------------------------------------- |
|
2749 // Searches the Entry tree for Function sections. |
|
2750 // If found they are stored in their class or in the global list. |
|
2751 |
|
2752 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd, |
|
2753 const QCString &rname,bool isFriend) |
|
2754 { |
|
2755 Entry *root = rootNav->entry(); |
|
2756 FileDef *fd=rootNav->fileDef(); |
|
2757 |
|
2758 int l,i=-1; |
|
2759 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*"); |
|
2760 |
|
2761 if (!root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable |
|
2762 { |
|
2763 root->args+=root->type.right(root->type.length()-i-l); |
|
2764 root->type=root->type.left(i+l); |
|
2765 } |
|
2766 |
|
2767 QCString name=removeRedundantWhiteSpace(rname); |
|
2768 if (name.left(2)=="::") name=name.right(name.length()-2); |
|
2769 |
|
2770 MemberDef::MemberType mtype; |
|
2771 if (isFriend) mtype=MemberDef::Friend; |
|
2772 else if (root->mtype==Signal) mtype=MemberDef::Signal; |
|
2773 else if (root->mtype==Slot) mtype=MemberDef::Slot; |
|
2774 else if (root->mtype==DCOP) mtype=MemberDef::DCOP; |
|
2775 else mtype=MemberDef::Function; |
|
2776 |
|
2777 // strip redundant template specifier for constructors |
|
2778 if ((fd==0 || getLanguageFromFileName(fd->name())==SrcLangExt_Cpp) && |
|
2779 name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1) |
|
2780 { |
|
2781 name=name.left(i); |
|
2782 } |
|
2783 if (Config_getBool("PREPROCESS_INCLUDES")) { |
|
2784 // If we are preprocessing the #included files we might have seen |
|
2785 // this member more than once so we |
|
2786 // only add a member where one did not exist before |
|
2787 QCString myDefName = name; |
|
2788 myDefName.append(root->args); |
|
2789 if(cd->hasFunction(myDefName, root->protection)) { |
|
2790 //if (Doxygen::memberNameSDict->find(name)) { |
|
2791 //printf("addMethodToClass() rejecting: %p %d %s::%s\n", cd, root->protection, cd->name().data(), myDefName.data()); |
|
2792 return; |
|
2793 } |
|
2794 //printf("addMethodToClass() accepting: %p %d %s::%s\n", cd, root->protection, cd->name().data(), myDefName.data()); |
|
2795 } |
|
2796 |
|
2797 //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", |
|
2798 // root->name.data(),root->args.data(),argListToString(root->argList).data() |
|
2799 // ); |
|
2800 |
|
2801 // adding class member |
|
2802 MemberDef *md=new MemberDef( |
|
2803 root->fileName,root->startLine, |
|
2804 root->type,name,root->args,root->exception, |
|
2805 root->protection,root->virt, |
|
2806 root->stat && root->relatesType != MemberOf, |
|
2807 root->relates.isEmpty() ? Member : |
|
2808 root->relatesType == MemberOf ? Foreign : Related, |
|
2809 mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList); |
|
2810 md->setTagInfo(rootNav->tagInfo()); |
|
2811 md->setMemberClass(cd); |
|
2812 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
2813 md->setDocsForDefinition(!root->proto); |
|
2814 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
2815 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
2816 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
2817 md->setMemberSpecifiers(root->spec); |
|
2818 md->setMemberGroupId(root->mGrpId); |
|
2819 md->setTypeConstraints(root->typeConstr); |
|
2820 md->setBodyDef(fd); |
|
2821 md->setFileDef(fd); |
|
2822 //md->setScopeTemplateArguments(root->tArgList); |
|
2823 md->addSectionsToDefinition(root->anchors); |
|
2824 QCString def; |
|
2825 QCString qualScope = cd->qualifiedNameWithTemplateParameters(); |
|
2826 QCString scopeSeparator="::"; |
|
2827 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA")) |
|
2828 { |
|
2829 qualScope = substitute(qualScope,"::","."); |
|
2830 scopeSeparator="."; |
|
2831 } |
|
2832 if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES")) |
|
2833 { |
|
2834 if (!root->type.isEmpty()) |
|
2835 { |
|
2836 if (root->argList) |
|
2837 { |
|
2838 def=root->type+" "+name; |
|
2839 } |
|
2840 else |
|
2841 { |
|
2842 def=root->type+" "+name+root->args; |
|
2843 } |
|
2844 } |
|
2845 else |
|
2846 { |
|
2847 if (root->argList) |
|
2848 { |
|
2849 def=name; |
|
2850 } |
|
2851 else |
|
2852 { |
|
2853 def=name+root->args; |
|
2854 } |
|
2855 } |
|
2856 } |
|
2857 else |
|
2858 { |
|
2859 if (!root->type.isEmpty()) |
|
2860 { |
|
2861 if (root->argList) |
|
2862 { |
|
2863 def=root->type+" "+qualScope+scopeSeparator+name; |
|
2864 } |
|
2865 else |
|
2866 { |
|
2867 def=root->type+" "+qualScope+scopeSeparator+name+root->args; |
|
2868 } |
|
2869 } |
|
2870 else |
|
2871 { |
|
2872 if (root->argList) |
|
2873 { |
|
2874 def=qualScope+scopeSeparator+name; |
|
2875 } |
|
2876 else |
|
2877 { |
|
2878 def=qualScope+scopeSeparator+name+root->args; |
|
2879 } |
|
2880 } |
|
2881 } |
|
2882 if (def.left(7)=="friend ") def=def.right(def.length()-7); |
|
2883 md->setDefinition(def); |
|
2884 md->enableCallGraph(root->callGraph); |
|
2885 md->enableCallerGraph(root->callerGraph); |
|
2886 |
|
2887 Debug::print(Debug::Functions,0, |
|
2888 " Func Member:\n" |
|
2889 " `%s' `%s'::`%s' `%s' proto=%d\n" |
|
2890 " def=`%s'\n", |
|
2891 root->type.data(), |
|
2892 qualScope.data(), |
|
2893 rname.data(), |
|
2894 root->args.data(), |
|
2895 root->proto, |
|
2896 def.data() |
|
2897 ); |
|
2898 |
|
2899 // add member to the global list of all members |
|
2900 //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data()); |
|
2901 MemberName *mn; |
|
2902 if ((mn=Doxygen::memberNameSDict->find(name))) |
|
2903 { |
|
2904 mn->append(md); |
|
2905 } |
|
2906 else |
|
2907 { |
|
2908 mn = new MemberName(name); |
|
2909 mn->append(md); |
|
2910 Doxygen::memberNameSDict->append(name,mn); |
|
2911 } |
|
2912 |
|
2913 // add member to the class cd |
|
2914 cd->insertMember(md); |
|
2915 // add file to list of used files |
|
2916 cd->insertUsedFile(root->fileName); |
|
2917 |
|
2918 addMemberToGroups(root,md); |
|
2919 rootNav->changeSection(Entry::EMPTY_SEC); |
|
2920 md->setRefItems(root->sli); |
|
2921 } |
|
2922 |
|
2923 |
|
2924 static void buildFunctionList(EntryNav *rootNav) |
|
2925 { |
|
2926 if (rootNav->section()==Entry::FUNCTION_SEC) |
|
2927 { |
|
2928 rootNav->loadEntry(g_storage); |
|
2929 Entry *root = rootNav->entry(); |
|
2930 |
|
2931 Debug::print(Debug::Functions,0, |
|
2932 "FUNCTION_SEC:\n" |
|
2933 " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%d proto=%d docFile=%s\n", |
|
2934 root->type.data(), |
|
2935 rootNav->parent()->name().data(), |
|
2936 root->name.data(), |
|
2937 root->args.data(), |
|
2938 root->relates.data(), |
|
2939 root->relatesType, |
|
2940 root->fileName.data(), |
|
2941 root->startLine, |
|
2942 root->bodyLine, |
|
2943 root->tArgLists ? (int)root->tArgLists->count() : -1, |
|
2944 root->mGrpId, |
|
2945 root->spec, |
|
2946 root->proto, |
|
2947 root->docFile.data() |
|
2948 ); |
|
2949 |
|
2950 bool isFriend=root->type.find("friend ")!=-1; |
|
2951 QCString rname = removeRedundantWhiteSpace(root->name); |
|
2952 //printf("rname=%s\n",rname.data()); |
|
2953 |
|
2954 QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name); |
|
2955 if (!rname.isEmpty() && scope.find('@')==-1) |
|
2956 { |
|
2957 ClassDef *cd=0; |
|
2958 // check if this function's parent is a class |
|
2959 scope=stripTemplateSpecifiersFromScope(scope,FALSE); |
|
2960 |
|
2961 FileDef *rfd=rootNav->fileDef(); |
|
2962 |
|
2963 int memIndex=rname.findRev("::"); |
|
2964 |
|
2965 cd=getClass(scope); |
|
2966 if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A |
|
2967 { |
|
2968 // strip scope from name |
|
2969 rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); |
|
2970 } |
|
2971 |
|
2972 NamespaceDef *nd = 0; |
|
2973 bool isMember=FALSE; |
|
2974 if (memIndex!=-1) |
|
2975 { |
|
2976 int ts=rname.find('<'); |
|
2977 int te=rname.find('>'); |
|
2978 if (memIndex>0 && (ts==-1 || te==-1)) |
|
2979 { |
|
2980 // note: the following code was replaced by inMember=TRUE to deal with a |
|
2981 // function rname='X::foo' of class X inside a namespace also called X... |
|
2982 // bug id 548175 |
|
2983 //nd = Doxygen::namespaceSDict->find(rname.left(memIndex)); |
|
2984 //isMember = nd==0; |
|
2985 //if (nd) |
|
2986 //{ |
|
2987 // // strip namespace scope from name |
|
2988 // scope=rname.left(memIndex); |
|
2989 // rname=rname.right(rname.length()-memIndex-2); |
|
2990 //} |
|
2991 isMember = TRUE; |
|
2992 } |
|
2993 else |
|
2994 { |
|
2995 isMember=memIndex<ts || memIndex>te; |
|
2996 } |
|
2997 } |
|
2998 |
|
2999 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*"); |
|
3000 if (!rootNav->parent()->name().isEmpty() && |
|
3001 (rootNav->parent()->section() & Entry::COMPOUND_MASK) && |
|
3002 cd && |
|
3003 // do some fuzzy things to exclude function pointers |
|
3004 (root->type.isEmpty() || |
|
3005 (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) || // type contains ..(..* and args not )[.. -> function pointer |
|
3006 root->type.find(")(")!=-1 || root->type.find("operator")!=-1 // type contains ..)(.. and not "operator" |
|
3007 ) |
|
3008 ) |
|
3009 { |
|
3010 Debug::print(Debug::Functions,0," --> member %s of class %s!\n", |
|
3011 rname.data(),cd->name().data()); |
|
3012 addMethodToClass(rootNav,cd,rname,isFriend); |
|
3013 } |
|
3014 else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) |
|
3015 || rootNav->parent()->section()==Entry::OBJCIMPL_SEC |
|
3016 ) && |
|
3017 !isMember && |
|
3018 (root->relates.isEmpty() || root->relatesType == Duplicate) && |
|
3019 root->type.left(7)!="extern " && root->type.left(8)!="typedef " |
|
3020 ) |
|
3021 // no member => unrelated function |
|
3022 { |
|
3023 /* check the uniqueness of the function name in the file. |
|
3024 * A file could contain a function prototype and a function definition |
|
3025 * or even multiple function prototypes. |
|
3026 */ |
|
3027 bool found=FALSE; |
|
3028 MemberName *mn; |
|
3029 MemberDef *md=0; |
|
3030 if ((mn=Doxygen::functionNameSDict->find(rname))) |
|
3031 { |
|
3032 Debug::print(Debug::Functions,0," --> function %s already found!\n",rname.data()); |
|
3033 MemberNameIterator mni(*mn); |
|
3034 for (mni.toFirst();(!found && (md=mni.current()));++mni) |
|
3035 { |
|
3036 NamespaceDef *mnd = md->getNamespaceDef(); |
|
3037 NamespaceDef *rnd = 0; |
|
3038 //printf("root namespace=%s\n",rootNav->parent()->name().data()); |
|
3039 QCString fullScope = scope; |
|
3040 QCString parentScope = rootNav->parent()->name(); |
|
3041 if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope)) |
|
3042 { |
|
3043 if (!scope.isEmpty()) fullScope.prepend("::"); |
|
3044 fullScope.prepend(parentScope); |
|
3045 } |
|
3046 //printf("fullScope=%s\n",fullScope.data()); |
|
3047 rnd = getResolvedNamespace(fullScope); |
|
3048 FileDef *mfd = md->getFileDef(); |
|
3049 QCString nsName,rnsName; |
|
3050 if (mnd) nsName = mnd->name().copy(); |
|
3051 if (rnd) rnsName = rnd->name().copy(); |
|
3052 //printf("matching arguments for %s%s %s%s\n", |
|
3053 // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data()); |
|
3054 LockingPtr<ArgumentList> mdAl = md->argumentList(); |
|
3055 LockingPtr<ArgumentList> mdTempl = md->templateArguments(); |
|
3056 |
|
3057 // in case of template functions, we need to check if the |
|
3058 // functions have the same number of template parameters |
|
3059 bool sameNumTemplateArgs = TRUE; |
|
3060 if (mdTempl!=0 && root->tArgLists) |
|
3061 { |
|
3062 if (mdTempl->count()!=root->tArgLists->getLast()->count()) |
|
3063 { |
|
3064 sameNumTemplateArgs = FALSE; |
|
3065 } |
|
3066 } |
|
3067 if ( |
|
3068 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(), |
|
3069 rnd ? rnd : Doxygen::globalScope,rfd,root->argList, |
|
3070 FALSE) && |
|
3071 sameNumTemplateArgs |
|
3072 ) |
|
3073 { |
|
3074 GroupDef *gd=0; |
|
3075 if (root->groups->first()!=0) |
|
3076 { |
|
3077 gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data()); |
|
3078 } |
|
3079 //printf("match!\n"); |
|
3080 //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data()); |
|
3081 // see if we need to create a new member |
|
3082 found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace |
|
3083 ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and |
|
3084 mfd->absFilePath()==root->fileName // prototype in the same file |
|
3085 ) |
|
3086 ); |
|
3087 // otherwise, allow a duplicate global member with the same argument list |
|
3088 if (!found && gd && gd==md->getGroupDef()) |
|
3089 { |
|
3090 // member is already in the group, so we don't want to add it again. |
|
3091 found=TRUE; |
|
3092 } |
|
3093 |
|
3094 //printf("combining function with prototype found=%d in namespace %s\n", |
|
3095 // found,nsName.data()); |
|
3096 |
|
3097 if (found) |
|
3098 { |
|
3099 // merge argument lists |
|
3100 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty()); |
|
3101 // merge documentation |
|
3102 if (md->documentation().isEmpty() && !root->doc.isEmpty()) |
|
3103 { |
|
3104 ArgumentList *argList = new ArgumentList; |
|
3105 stringToArgumentList(root->args,argList); |
|
3106 if (root->proto) |
|
3107 { |
|
3108 //printf("setDeclArgumentList to %p\n",argList); |
|
3109 md->setDeclArgumentList(argList); |
|
3110 } |
|
3111 else |
|
3112 { |
|
3113 md->setArgumentList(argList); |
|
3114 } |
|
3115 } |
|
3116 |
|
3117 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
3118 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
3119 md->setDocsForDefinition(!root->proto); |
|
3120 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
3121 md->setBodyDef(rfd); |
|
3122 |
|
3123 if (md->briefDescription().isEmpty() && !root->brief.isEmpty()) |
|
3124 { |
|
3125 md->setArgsString(root->args); |
|
3126 } |
|
3127 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
3128 |
|
3129 md->addSectionsToDefinition(root->anchors); |
|
3130 |
|
3131 md->enableCallGraph(md->hasCallGraph() || root->callGraph); |
|
3132 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph); |
|
3133 |
|
3134 // merge ingroup specifiers |
|
3135 if (md->getGroupDef()==0 && root->groups->first()!=0) |
|
3136 { |
|
3137 addMemberToGroups(root,md); |
|
3138 } |
|
3139 else if (md->getGroupDef()!=0 && root->groups->count()==0) |
|
3140 { |
|
3141 //printf("existing member is grouped, new member not\n"); |
|
3142 root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri())); |
|
3143 } |
|
3144 else if (md->getGroupDef()!=0 && root->groups->first()!=0) |
|
3145 { |
|
3146 //printf("both members are grouped\n"); |
|
3147 } |
|
3148 |
|
3149 // if md is a declaration and root is the corresponding |
|
3150 // definition, then turn md into a definition. |
|
3151 if (md->isPrototype() && !root->proto) |
|
3152 { |
|
3153 md->setPrototype(FALSE); |
|
3154 } |
|
3155 } |
|
3156 } |
|
3157 } |
|
3158 } |
|
3159 if (!found) /* global function is unique with respect to the file */ |
|
3160 { |
|
3161 Debug::print(Debug::Functions,0," --> new function %s found!\n",rname.data()); |
|
3162 //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n", |
|
3163 // root->type.data(),rname.data(),root->args.data(),root->bodyLine); |
|
3164 |
|
3165 // new global function |
|
3166 ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0; |
|
3167 QCString name=removeRedundantWhiteSpace(rname); |
|
3168 md=new MemberDef( |
|
3169 root->fileName,root->startLine, |
|
3170 root->type,name,root->args,root->exception, |
|
3171 root->protection,root->virt,root->stat,Member, |
|
3172 MemberDef::Function,tArgList,root->argList); |
|
3173 |
|
3174 md->setTagInfo(rootNav->tagInfo()); |
|
3175 //md->setDefFile(root->fileName); |
|
3176 //md->setDefLine(root->startLine); |
|
3177 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
3178 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
3179 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
3180 md->setPrototype(root->proto); |
|
3181 md->setDocsForDefinition(!root->proto); |
|
3182 md->setTypeConstraints(root->typeConstr); |
|
3183 //md->setBody(root->body); |
|
3184 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
3185 FileDef *fd=rootNav->fileDef(); |
|
3186 md->setBodyDef(fd); |
|
3187 md->addSectionsToDefinition(root->anchors); |
|
3188 md->setMemberSpecifiers(root->spec); |
|
3189 md->setMemberGroupId(root->mGrpId); |
|
3190 |
|
3191 // see if the function is inside a namespace that was not part of |
|
3192 // the name already (in that case nd should be non-zero already) |
|
3193 if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC ) |
|
3194 { |
|
3195 //QCString nscope=removeAnonymousScopes(rootNav->parent()->name()); |
|
3196 QCString nscope=rootNav->parent()->name(); |
|
3197 if (!nscope.isEmpty()) |
|
3198 { |
|
3199 nd = getResolvedNamespace(nscope); |
|
3200 } |
|
3201 } |
|
3202 |
|
3203 if (!scope.isEmpty()) |
|
3204 { |
|
3205 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA")) |
|
3206 { |
|
3207 scope = substitute(scope,"::",".")+"."; |
|
3208 } |
|
3209 else |
|
3210 { |
|
3211 scope+="::"; |
|
3212 } |
|
3213 } |
|
3214 |
|
3215 QCString def; |
|
3216 if (!root->type.isEmpty()) |
|
3217 { |
|
3218 if (root->argList) |
|
3219 { |
|
3220 def=root->type+" "+scope+name; |
|
3221 } |
|
3222 else |
|
3223 { |
|
3224 def=root->type+" "+scope+name+root->args; |
|
3225 } |
|
3226 } |
|
3227 else |
|
3228 { |
|
3229 if (root->argList) |
|
3230 { |
|
3231 def=scope+name.copy(); |
|
3232 } |
|
3233 else |
|
3234 { |
|
3235 def=scope+name+root->args; |
|
3236 } |
|
3237 } |
|
3238 Debug::print(Debug::Functions,0, |
|
3239 " Global Function:\n" |
|
3240 " `%s' `%s'::`%s' `%s' proto=%d\n" |
|
3241 " def=`%s'\n", |
|
3242 root->type.data(), |
|
3243 rootNav->parent()->name().data(), |
|
3244 rname.data(), |
|
3245 root->args.data(), |
|
3246 root->proto, |
|
3247 def.data() |
|
3248 ); |
|
3249 md->setDefinition(def); |
|
3250 md->enableCallGraph(root->callGraph); |
|
3251 md->enableCallerGraph(root->callerGraph); |
|
3252 //if (root->mGrpId!=-1) |
|
3253 //{ |
|
3254 // md->setMemberGroup(memberGroupDict[root->mGrpId]); |
|
3255 //} |
|
3256 |
|
3257 md->setRefItems(root->sli); |
|
3258 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') |
|
3259 { |
|
3260 // add member to namespace |
|
3261 md->setNamespace(nd); |
|
3262 nd->insertMember(md); |
|
3263 } |
|
3264 if (fd) |
|
3265 { |
|
3266 // add member to the file (we do this even if we have already |
|
3267 // inserted it into the namespace) |
|
3268 md->setFileDef(fd); |
|
3269 fd->insertMember(md); |
|
3270 } |
|
3271 |
|
3272 // add member to the list of file members |
|
3273 //printf("Adding member=%s\n",md->name().data()); |
|
3274 MemberName *mn; |
|
3275 if ((mn=Doxygen::functionNameSDict->find(name))) |
|
3276 { |
|
3277 mn->append(md); |
|
3278 } |
|
3279 else |
|
3280 { |
|
3281 mn = new MemberName(name); |
|
3282 mn->append(md); |
|
3283 Doxygen::functionNameSDict->append(name,mn); |
|
3284 } |
|
3285 addMemberToGroups(root,md); |
|
3286 if (root->relatesType == Simple) // if this is a relatesalso command, |
|
3287 // allow find Member to pick it up |
|
3288 { |
|
3289 rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished |
|
3290 // with this entry. |
|
3291 |
|
3292 } |
|
3293 } |
|
3294 else |
|
3295 { |
|
3296 FileDef *fd=rootNav->fileDef(); |
|
3297 if (fd) |
|
3298 { |
|
3299 // add member to the file (we do this even if we have already |
|
3300 // inserted it into the namespace) |
|
3301 fd->insertMember(md); |
|
3302 } |
|
3303 } |
|
3304 |
|
3305 //printf("unrelated function %d `%s' `%s' `%s'\n", |
|
3306 // root->parent->section,root->type.data(),rname.data(),root->args.data()); |
|
3307 } |
|
3308 else |
|
3309 { |
|
3310 Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data()); |
|
3311 } |
|
3312 } |
|
3313 else if (rname.isEmpty()) |
|
3314 { |
|
3315 warn(root->fileName,root->startLine, |
|
3316 "Warning: Illegal member name found." |
|
3317 ); |
|
3318 } |
|
3319 |
|
3320 rootNav->releaseEntry(); |
|
3321 } |
|
3322 RECURSE_ENTRYTREE(buildFunctionList,rootNav); |
|
3323 } |
|
3324 |
|
3325 //---------------------------------------------------------------------- |
|
3326 |
|
3327 static void findFriends() |
|
3328 { |
|
3329 //printf("findFriends()\n"); |
|
3330 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); |
|
3331 MemberName *fn; |
|
3332 for (;(fn=fnli.current());++fnli) // for each global function name |
|
3333 { |
|
3334 //printf("Function name=`%s'\n",fn->memberName()); |
|
3335 MemberName *mn; |
|
3336 if ((mn=Doxygen::memberNameSDict->find(fn->memberName()))) |
|
3337 { // there are members with the same name |
|
3338 //printf("Function name is also a member name\n"); |
|
3339 MemberNameIterator fni(*fn); |
|
3340 MemberDef *fmd; |
|
3341 for (;(fmd=fni.current());++fni) // for each function with that name |
|
3342 { |
|
3343 MemberNameIterator mni(*mn); |
|
3344 MemberDef *mmd; |
|
3345 for (;(mmd=mni.current());++mni) // for each member with that name |
|
3346 { |
|
3347 //printf("Checking for matching arguments |
|
3348 // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n", |
|
3349 // mmd->isRelated(),mmd->isFriend(),mmd->isFunction()); |
|
3350 LockingPtr<ArgumentList> mmdAl = mmd->argumentList(); |
|
3351 LockingPtr<ArgumentList> fmdAl = fmd->argumentList(); |
|
3352 if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) && |
|
3353 matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(), |
|
3354 fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(), |
|
3355 TRUE |
|
3356 ) |
|
3357 |
|
3358 ) // if the member is related and the arguments match then the |
|
3359 // function is actually a friend. |
|
3360 { |
|
3361 mergeArguments(mmdAl.pointer(),fmdAl.pointer()); |
|
3362 if (!fmd->documentation().isEmpty()) |
|
3363 { |
|
3364 mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine()); |
|
3365 } |
|
3366 else if (!mmd->documentation().isEmpty()) |
|
3367 { |
|
3368 fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine()); |
|
3369 } |
|
3370 if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty()) |
|
3371 { |
|
3372 mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine()); |
|
3373 } |
|
3374 else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty()) |
|
3375 { |
|
3376 fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine()); |
|
3377 } |
|
3378 if (!fmd->inbodyDocumentation().isEmpty()) |
|
3379 { |
|
3380 mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine()); |
|
3381 } |
|
3382 else if (!mmd->inbodyDocumentation().isEmpty()) |
|
3383 { |
|
3384 fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine()); |
|
3385 } |
|
3386 //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine()); |
|
3387 if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1) |
|
3388 { |
|
3389 mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine()); |
|
3390 mmd->setBodyDef(fmd->getBodyDef()); |
|
3391 //mmd->setBodyMember(fmd); |
|
3392 } |
|
3393 else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1) |
|
3394 { |
|
3395 fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine()); |
|
3396 fmd->setBodyDef(mmd->getBodyDef()); |
|
3397 //fmd->setBodyMember(mmd); |
|
3398 } |
|
3399 mmd->setDocsForDefinition(fmd->isDocsForDefinition()); |
|
3400 |
|
3401 mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph()); |
|
3402 mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph()); |
|
3403 fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph()); |
|
3404 fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph()); |
|
3405 } |
|
3406 } |
|
3407 } |
|
3408 } |
|
3409 } |
|
3410 } |
|
3411 |
|
3412 //---------------------------------------------------------------------- |
|
3413 |
|
3414 static void transferArgumentDocumentation(ArgumentList *decAl,ArgumentList *defAl) |
|
3415 { |
|
3416 if (decAl && defAl) |
|
3417 { |
|
3418 ArgumentListIterator decAli(*decAl); |
|
3419 ArgumentListIterator defAli(*defAl); |
|
3420 Argument *decA,*defA; |
|
3421 for (decAli.toFirst(),defAli.toFirst(); |
|
3422 (decA=decAli.current()) && (defA=defAli.current()); |
|
3423 ++decAli,++defAli) |
|
3424 { |
|
3425 //printf("Argument decA->name=%s (doc=%s) defA->name=%s (doc=%s)\n", |
|
3426 // decA->name.data(),decA->docs.data(), |
|
3427 // defA->name.data(),defA->docs.data() |
|
3428 // ); |
|
3429 if (decA->docs.isEmpty() && !defA->docs.isEmpty()) |
|
3430 { |
|
3431 decA->docs = defA->docs.copy(); |
|
3432 } |
|
3433 else if (defA->docs.isEmpty() && !decA->docs.isEmpty()) |
|
3434 { |
|
3435 defA->docs = decA->docs.copy(); |
|
3436 } |
|
3437 } |
|
3438 } |
|
3439 } |
|
3440 |
|
3441 static void transferFunctionDocumentation() |
|
3442 { |
|
3443 //printf("---- transferFunctionDocumentation()\n"); |
|
3444 |
|
3445 // find matching function declaration and definitions. |
|
3446 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); |
|
3447 MemberName *mn; |
|
3448 for (;(mn=mnli.current());++mnli) |
|
3449 { |
|
3450 //printf("memberName=%s count=%d\n",mn->memberName(),mn->count()); |
|
3451 MemberDef *mdef=0,*mdec=0; |
|
3452 MemberNameIterator mni1(*mn); |
|
3453 /* find a matching function declaration and definition for this function */ |
|
3454 for (;(mdec=mni1.current());++mni1) |
|
3455 { |
|
3456 //printf("mdec=%s isPrototype()=%d\n",mdec->name().data(),mdec->isPrototype()); |
|
3457 if (mdec->isPrototype() || |
|
3458 (mdec->isVariable() && mdec->isExternal()) |
|
3459 ) |
|
3460 { |
|
3461 MemberNameIterator mni2(*mn); |
|
3462 for (;(mdef=mni2.current());++mni2) |
|
3463 { |
|
3464 if ( |
|
3465 (mdef->isFunction() && !mdef->isStatic() && !mdef->isPrototype()) || |
|
3466 (mdef->isVariable() && !mdef->isExternal() && !mdef->isStatic()) |
|
3467 ) |
|
3468 { |
|
3469 //printf("mdef=(%p,%s) mdec=(%p,%s)\n", |
|
3470 // mdef, mdef ? mdef->name().data() : "", |
|
3471 // mdec, mdec ? mdec->name().data() : ""); |
|
3472 |
|
3473 LockingPtr<ArgumentList> mdefAl = mdef->argumentList(); |
|
3474 LockingPtr<ArgumentList> mdecAl = mdec->argumentList(); |
|
3475 if (matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(), |
|
3476 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(), |
|
3477 TRUE |
|
3478 ) |
|
3479 ) /* match found */ |
|
3480 { |
|
3481 //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n", |
|
3482 // mn->memberName(), |
|
3483 // mdef->getFileDef()->name().data(),mdef->documentation().data(), |
|
3484 // mdec->getFileDef()->name().data(),mdec->documentation().data() |
|
3485 // ); |
|
3486 |
|
3487 // first merge argument documentation |
|
3488 transferArgumentDocumentation(mdecAl.pointer(),mdefAl.pointer()); |
|
3489 |
|
3490 /* copy documentation between function definition and declaration */ |
|
3491 if (!mdec->briefDescription().isEmpty()) |
|
3492 { |
|
3493 mdef->setBriefDescription(mdec->briefDescription(),mdec->briefFile(),mdec->briefLine()); |
|
3494 } |
|
3495 else if (!mdef->briefDescription().isEmpty()) |
|
3496 { |
|
3497 mdec->setBriefDescription(mdef->briefDescription(),mdef->briefFile(),mdef->briefLine()); |
|
3498 } |
|
3499 if (!mdef->documentation().isEmpty()) |
|
3500 { |
|
3501 //printf("transfering docs mdef->mdec (%s->%s)\n",mdef->argsString(),mdec->argsString()); |
|
3502 mdec->setDocumentation(mdef->documentation(),mdef->docFile(),mdef->docLine()); |
|
3503 mdec->setDocsForDefinition(mdef->isDocsForDefinition()); |
|
3504 if (mdefAl!=0) |
|
3505 { |
|
3506 ArgumentList *mdefAlComb = new ArgumentList; |
|
3507 stringToArgumentList(mdef->argsString(),mdefAlComb); |
|
3508 transferArgumentDocumentation(mdefAl.pointer(),mdefAlComb); |
|
3509 mdec->setArgumentList(mdefAlComb); |
|
3510 } |
|
3511 } |
|
3512 else if (!mdec->documentation().isEmpty()) |
|
3513 { |
|
3514 //printf("transfering docs mdec->mdef (%s->%s)\n",mdec->argsString(),mdef->argsString()); |
|
3515 mdef->setDocumentation(mdec->documentation(),mdec->docFile(),mdec->docLine()); |
|
3516 mdef->setDocsForDefinition(mdec->isDocsForDefinition()); |
|
3517 if (mdecAl!=0) |
|
3518 { |
|
3519 ArgumentList *mdecAlComb = new ArgumentList; |
|
3520 stringToArgumentList(mdec->argsString(),mdecAlComb); |
|
3521 transferArgumentDocumentation(mdecAl.pointer(),mdecAlComb); |
|
3522 mdef->setDeclArgumentList(mdecAlComb); |
|
3523 } |
|
3524 } |
|
3525 if (!mdef->inbodyDocumentation().isEmpty()) |
|
3526 { |
|
3527 mdec->setInbodyDocumentation(mdef->inbodyDocumentation(),mdef->inbodyFile(),mdef->inbodyLine()); |
|
3528 } |
|
3529 else if (!mdec->inbodyDocumentation().isEmpty()) |
|
3530 { |
|
3531 mdef->setInbodyDocumentation(mdec->inbodyDocumentation(),mdec->inbodyFile(),mdec->inbodyLine()); |
|
3532 } |
|
3533 if (mdec->getStartBodyLine()!=-1 && mdef->getStartBodyLine()==-1) |
|
3534 { |
|
3535 //printf("body mdec->mdef %d-%d\n",mdec->getStartBodyLine(),mdef->getEndBodyLine()); |
|
3536 mdef->setBodySegment(mdec->getStartBodyLine(),mdec->getEndBodyLine()); |
|
3537 mdef->setBodyDef(mdec->getBodyDef()); |
|
3538 //mdef->setBodyMember(mdec); |
|
3539 } |
|
3540 else if (mdef->getStartBodyLine()!=-1 && mdec->getStartBodyLine()==-1) |
|
3541 { |
|
3542 //printf("body mdef->mdec %d-%d\n",mdef->getStartBodyLine(),mdec->getEndBodyLine()); |
|
3543 mdec->setBodySegment(mdef->getStartBodyLine(),mdef->getEndBodyLine()); |
|
3544 mdec->setBodyDef(mdef->getBodyDef()); |
|
3545 //mdec->setBodyMember(mdef); |
|
3546 } |
|
3547 mdec->mergeMemberSpecifiers(mdef->getMemberSpecifiers()); |
|
3548 mdef->mergeMemberSpecifiers(mdec->getMemberSpecifiers()); |
|
3549 |
|
3550 |
|
3551 // copy group info. |
|
3552 if (mdec->getGroupDef()==0 && mdef->getGroupDef()!=0) |
|
3553 { |
|
3554 mdec->setGroupDef(mdef->getGroupDef(), |
|
3555 mdef->getGroupPri(), |
|
3556 mdef->docFile(), |
|
3557 mdef->docLine(), |
|
3558 mdef->hasDocumentation(), |
|
3559 mdef |
|
3560 ); |
|
3561 } |
|
3562 else if (mdef->getGroupDef()==0 && mdec->getGroupDef()!=0) |
|
3563 { |
|
3564 mdef->setGroupDef(mdec->getGroupDef(), |
|
3565 mdec->getGroupPri(), |
|
3566 mdec->docFile(), |
|
3567 mdec->docLine(), |
|
3568 mdec->hasDocumentation(), |
|
3569 mdec |
|
3570 ); |
|
3571 } |
|
3572 |
|
3573 |
|
3574 mdec->mergeRefItems(mdef); |
|
3575 mdef->mergeRefItems(mdec); |
|
3576 |
|
3577 mdef->setMemberDeclaration(mdec); |
|
3578 mdec->setMemberDefinition(mdef); |
|
3579 |
|
3580 mdef->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph()); |
|
3581 mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph()); |
|
3582 mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph()); |
|
3583 mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph()); |
|
3584 } |
|
3585 } |
|
3586 } |
|
3587 } |
|
3588 } |
|
3589 } |
|
3590 } |
|
3591 |
|
3592 //---------------------------------------------------------------------- |
|
3593 |
|
3594 static void transferFunctionReferences() |
|
3595 { |
|
3596 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); |
|
3597 MemberName *mn; |
|
3598 for (;(mn=mnli.current());++mnli) |
|
3599 { |
|
3600 MemberDef *md,*mdef=0,*mdec=0; |
|
3601 MemberNameIterator mni(*mn); |
|
3602 /* find a matching function declaration and definition for this function */ |
|
3603 for (;(md=mni.current());++mni) |
|
3604 { |
|
3605 if (md->isPrototype()) |
|
3606 mdec=md; |
|
3607 else if (md->isVariable() && md->isExternal()) |
|
3608 mdec=md; |
|
3609 |
|
3610 if (md->isFunction() && !md->isStatic() && !md->isPrototype()) |
|
3611 mdef=md; |
|
3612 else if (md->isVariable() && !md->isExternal() && !md->isStatic()) |
|
3613 mdef=md; |
|
3614 } |
|
3615 if (mdef && mdec) |
|
3616 { |
|
3617 LockingPtr<ArgumentList> mdefAl = mdef->argumentList(); |
|
3618 LockingPtr<ArgumentList> mdecAl = mdec->argumentList(); |
|
3619 if ( |
|
3620 matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(), |
|
3621 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(), |
|
3622 TRUE |
|
3623 ) |
|
3624 ) /* match found */ |
|
3625 { |
|
3626 LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers(); |
|
3627 LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers(); |
|
3628 if (defDict!=0) |
|
3629 { |
|
3630 MemberSDict::Iterator msdi(*defDict); |
|
3631 MemberDef *rmd; |
|
3632 for (msdi.toFirst();(rmd=msdi.current());++msdi) |
|
3633 { |
|
3634 if (decDict==0 || decDict->find(rmd->name())==0) |
|
3635 { |
|
3636 mdec->addSourceReferences(rmd); |
|
3637 } |
|
3638 } |
|
3639 } |
|
3640 if (decDict!=0) |
|
3641 { |
|
3642 MemberSDict::Iterator msdi(*decDict); |
|
3643 MemberDef *rmd; |
|
3644 for (msdi.toFirst();(rmd=msdi.current());++msdi) |
|
3645 { |
|
3646 if (defDict==0 || defDict->find(rmd->name())==0) |
|
3647 { |
|
3648 mdef->addSourceReferences(rmd); |
|
3649 } |
|
3650 } |
|
3651 } |
|
3652 |
|
3653 defDict = mdef->getReferencedByMembers(); |
|
3654 decDict = mdec->getReferencedByMembers(); |
|
3655 if (defDict!=0) |
|
3656 { |
|
3657 MemberSDict::Iterator msdi(*defDict); |
|
3658 MemberDef *rmd; |
|
3659 for (msdi.toFirst();(rmd=msdi.current());++msdi) |
|
3660 { |
|
3661 if (decDict==0 || decDict->find(rmd->name())==0) |
|
3662 { |
|
3663 mdec->addSourceReferencedBy(rmd); |
|
3664 } |
|
3665 } |
|
3666 } |
|
3667 if (decDict!=0) |
|
3668 { |
|
3669 MemberSDict::Iterator msdi(*decDict); |
|
3670 MemberDef *rmd; |
|
3671 for (msdi.toFirst();(rmd=msdi.current());++msdi) |
|
3672 { |
|
3673 if (defDict==0 || defDict->find(rmd->name())==0) |
|
3674 { |
|
3675 mdef->addSourceReferencedBy(rmd); |
|
3676 } |
|
3677 } |
|
3678 } |
|
3679 } |
|
3680 } |
|
3681 } |
|
3682 } |
|
3683 |
|
3684 //---------------------------------------------------------------------- |
|
3685 |
|
3686 static void transferRelatedFunctionDocumentation() |
|
3687 { |
|
3688 // find match between function declaration and definition for |
|
3689 // related functions |
|
3690 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict); |
|
3691 MemberName *mn; |
|
3692 for (mnli.toFirst();(mn=mnli.current());++mnli) |
|
3693 { |
|
3694 MemberDef *md; |
|
3695 MemberNameIterator mni(*mn); |
|
3696 /* find a matching function declaration and definition for this function */ |
|
3697 for (mni.toFirst();(md=mni.current());++mni) // for each global function |
|
3698 { |
|
3699 //printf(" Function `%s'\n",md->name().data()); |
|
3700 MemberName *rmn; |
|
3701 if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name |
|
3702 { |
|
3703 //printf(" Member name found\n"); |
|
3704 MemberDef *rmd; |
|
3705 MemberNameIterator rmni(*rmn); |
|
3706 for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name |
|
3707 { |
|
3708 LockingPtr<ArgumentList> mdAl = md->argumentList(); |
|
3709 LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); |
|
3710 //printf(" Member found: related=`%d'\n",rmd->isRelated()); |
|
3711 if ((rmd->isRelated() || rmd->isForeign()) && // related function |
|
3712 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(), |
|
3713 rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), |
|
3714 TRUE |
|
3715 ) |
|
3716 ) |
|
3717 { |
|
3718 //printf(" Found related member `%s'\n",md->name().data()); |
|
3719 if (rmd->relatedAlso()) |
|
3720 md->setRelatedAlso(rmd->relatedAlso()); |
|
3721 else if (rmd->isForeign()) |
|
3722 md->makeForeign(); |
|
3723 else |
|
3724 md->makeRelated(); |
|
3725 } |
|
3726 } |
|
3727 } |
|
3728 } |
|
3729 } |
|
3730 } |
|
3731 |
|
3732 //---------------------------------------------------------------------- |
|
3733 |
|
3734 /*! make a dictionary of all template arguments of class cd |
|
3735 * that are part of the base class name. |
|
3736 * Example: A template class A with template arguments <R,S,T> |
|
3737 * that inherits from B<T,T,S> will have T and S in the dictionary. |
|
3738 */ |
|
3739 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name) |
|
3740 { |
|
3741 QDict<int> *templateNames = new QDict<int>(17); |
|
3742 templateNames->setAutoDelete(TRUE); |
|
3743 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*"); |
|
3744 if (templateArguments) |
|
3745 { |
|
3746 ArgumentListIterator ali(*templateArguments); |
|
3747 Argument *arg; |
|
3748 int count=0; |
|
3749 for (ali.toFirst();(arg=ali.current());++ali,count++) |
|
3750 { |
|
3751 int i,p=0,l; |
|
3752 while ((i=re.match(name,p,&l))!=-1) |
|
3753 { |
|
3754 QCString n = name.mid(i,l); |
|
3755 if (n==arg->name) |
|
3756 { |
|
3757 if (templateNames->find(n)==0) |
|
3758 { |
|
3759 templateNames->insert(n,new int(count)); |
|
3760 } |
|
3761 } |
|
3762 p=i+l; |
|
3763 } |
|
3764 } |
|
3765 } |
|
3766 return templateNames; |
|
3767 } |
|
3768 |
|
3769 /*! Searches a class from within \a context and \a cd and returns its |
|
3770 * definition if found (otherwise 0 is returned). |
|
3771 */ |
|
3772 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name) |
|
3773 { |
|
3774 FileDef *fd=cd->getFileDef(); |
|
3775 ClassDef *result=0; |
|
3776 if (context && cd!=context) |
|
3777 { |
|
3778 result = getResolvedClass(context,0,name,0,0,TRUE,TRUE); |
|
3779 } |
|
3780 if (result==0) |
|
3781 { |
|
3782 result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE); |
|
3783 } |
|
3784 //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n", |
|
3785 // name.data(), |
|
3786 // context ? context->name().data() : "<none>", |
|
3787 // cd ? cd->name().data() : "<none>", |
|
3788 // result ? result->name().data() : "<none>", |
|
3789 // Doxygen::classSDict.find(name) |
|
3790 // ); |
|
3791 return result; |
|
3792 } |
|
3793 |
|
3794 enum FindBaseClassRelation_Mode |
|
3795 { |
|
3796 TemplateInstances, |
|
3797 DocumentedOnly, |
|
3798 Undocumented |
|
3799 }; |
|
3800 |
|
3801 static bool findClassRelation( |
|
3802 EntryNav *rootNav, |
|
3803 Definition *context, |
|
3804 ClassDef *cd, |
|
3805 BaseInfo *bi, |
|
3806 QDict<int> *templateNames, |
|
3807 /*bool insertUndocumented*/ |
|
3808 FindBaseClassRelation_Mode mode, |
|
3809 bool isArtificial |
|
3810 ); |
|
3811 |
|
3812 |
|
3813 static void findUsedClassesForClass(EntryNav *rootNav, |
|
3814 Definition *context, |
|
3815 ClassDef *masterCd, |
|
3816 ClassDef *instanceCd, |
|
3817 bool isArtificial, |
|
3818 ArgumentList *actualArgs=0, |
|
3819 QDict<int> *templateNames=0 |
|
3820 ) |
|
3821 { |
|
3822 masterCd->visited=TRUE; |
|
3823 ArgumentList *formalArgs = masterCd->templateArguments(); |
|
3824 if (masterCd->memberNameInfoSDict()) |
|
3825 { |
|
3826 MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict()); |
|
3827 MemberNameInfo *mni; |
|
3828 for (;(mni=mnili.current());++mnili) |
|
3829 { |
|
3830 MemberNameInfoIterator mnii(*mni); |
|
3831 MemberInfo *mi; |
|
3832 for (mnii.toFirst();(mi=mnii.current());++mnii) |
|
3833 { |
|
3834 MemberDef *md=mi->memberDef; |
|
3835 if (md->isVariable()) // for each member variable in this class |
|
3836 { |
|
3837 //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data()); |
|
3838 QCString type=removeRedundantWhiteSpace(md->typeString()); |
|
3839 QCString typedefValue = resolveTypeDef(masterCd,type); |
|
3840 if (!typedefValue.isEmpty()) |
|
3841 { |
|
3842 type = typedefValue; |
|
3843 } |
|
3844 int pos=0; |
|
3845 QCString usedClassName; |
|
3846 QCString templSpec; |
|
3847 bool found=FALSE; |
|
3848 // the type can contain template variables, replace them if present |
|
3849 if (actualArgs) |
|
3850 { |
|
3851 type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs); |
|
3852 } |
|
3853 |
|
3854 //printf(" template substitution gives=%s\n",type.data()); |
|
3855 while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1) |
|
3856 { |
|
3857 // find the type (if any) that matches usedClassName |
|
3858 ClassDef *typeCd = getResolvedClass(masterCd, |
|
3859 masterCd->getFileDef(), |
|
3860 usedClassName, |
|
3861 0,0, |
|
3862 FALSE,TRUE |
|
3863 ); |
|
3864 //printf("====> usedClassName=%s -> typeCd=%s\n", |
|
3865 // usedClassName.data(),typeCd?typeCd->name().data():"<none>"); |
|
3866 if (typeCd) |
|
3867 { |
|
3868 usedClassName = typeCd->name(); |
|
3869 } |
|
3870 |
|
3871 int sp=usedClassName.find('<'); |
|
3872 if (sp==-1) sp=0; |
|
3873 int si=usedClassName.findRev("::",sp); |
|
3874 if (si!=-1) |
|
3875 { |
|
3876 // replace any namespace aliases |
|
3877 replaceNamespaceAliases(usedClassName,si); |
|
3878 } |
|
3879 // add any template arguments to the class |
|
3880 QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec); |
|
3881 //printf(" usedName=%s\n",usedName.data()); |
|
3882 |
|
3883 bool delTempNames=FALSE; |
|
3884 if (templateNames==0) |
|
3885 { |
|
3886 templateNames = getTemplateArgumentsInName(formalArgs,usedName); |
|
3887 delTempNames=TRUE; |
|
3888 } |
|
3889 BaseInfo bi(usedName,Public,Normal); |
|
3890 findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial); |
|
3891 |
|
3892 if (masterCd->templateArguments()) |
|
3893 { |
|
3894 ArgumentListIterator ali(*masterCd->templateArguments()); |
|
3895 Argument *arg; |
|
3896 int count=0; |
|
3897 for (ali.toFirst();(arg=ali.current());++ali,++count) |
|
3898 { |
|
3899 if (arg->name==usedName) // type is a template argument |
|
3900 { |
|
3901 found=TRUE; |
|
3902 Debug::print(Debug::Classes,0," New used class `%s'\n", usedName.data()); |
|
3903 |
|
3904 ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName); |
|
3905 if (usedCd==0) |
|
3906 { |
|
3907 usedCd = new ClassDef( |
|
3908 masterCd->getDefFileName(),masterCd->getDefLine(), |
|
3909 usedName,ClassDef::Class); |
|
3910 //printf("making %s a template argument!!!\n",usedCd->name().data()); |
|
3911 usedCd->makeTemplateArgument(); |
|
3912 usedCd->setUsedOnly(TRUE); |
|
3913 Doxygen::hiddenClasses->append(usedName,usedCd); |
|
3914 } |
|
3915 if (usedCd) |
|
3916 { |
|
3917 if (isArtificial) usedCd->setArtificial(TRUE); |
|
3918 Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", usedCd->name().data()); |
|
3919 instanceCd->addUsedClass(usedCd,md->name()); |
|
3920 usedCd->addUsedByClass(instanceCd,md->name()); |
|
3921 } |
|
3922 } |
|
3923 } |
|
3924 } |
|
3925 |
|
3926 if (!found) |
|
3927 { |
|
3928 ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName); |
|
3929 //printf("Looking for used class %s: result=%s master=%s\n", |
|
3930 // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>"); |
|
3931 |
|
3932 if (usedCd) |
|
3933 { |
|
3934 found=TRUE; |
|
3935 Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", usedCd->name().data()); |
|
3936 instanceCd->addUsedClass(usedCd,md->name()); // class exists |
|
3937 usedCd->addUsedByClass(instanceCd,md->name()); |
|
3938 } |
|
3939 } |
|
3940 if (delTempNames) |
|
3941 { |
|
3942 delete templateNames; |
|
3943 templateNames=0; |
|
3944 } |
|
3945 } |
|
3946 if (!found && !type.isEmpty()) // used class is not documented in any scope |
|
3947 { |
|
3948 ClassDef *usedCd = Doxygen::hiddenClasses->find(type); |
|
3949 if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS")) |
|
3950 { |
|
3951 if (type.right(2)=="(*") // type is a function pointer |
|
3952 { |
|
3953 type+=md->argsString(); |
|
3954 } |
|
3955 Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data()); |
|
3956 usedCd = new ClassDef( |
|
3957 masterCd->getDefFileName(),masterCd->getDefLine(), |
|
3958 type,ClassDef::Class); |
|
3959 usedCd->setUsedOnly(TRUE); |
|
3960 Doxygen::hiddenClasses->append(type,usedCd); |
|
3961 } |
|
3962 if (usedCd) |
|
3963 { |
|
3964 if (isArtificial) usedCd->setArtificial(TRUE); |
|
3965 Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", usedCd->name().data()); |
|
3966 instanceCd->addUsedClass(usedCd,md->name()); |
|
3967 usedCd->addUsedByClass(instanceCd,md->name()); |
|
3968 } |
|
3969 } |
|
3970 } |
|
3971 } |
|
3972 } |
|
3973 } |
|
3974 else |
|
3975 { |
|
3976 //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd); |
|
3977 } |
|
3978 } |
|
3979 |
|
3980 static void findBaseClassesForClass( |
|
3981 EntryNav *rootNav, |
|
3982 Definition *context, |
|
3983 ClassDef *masterCd, |
|
3984 ClassDef *instanceCd, |
|
3985 FindBaseClassRelation_Mode mode, |
|
3986 bool isArtificial, |
|
3987 ArgumentList *actualArgs=0, |
|
3988 QDict<int> *templateNames=0 |
|
3989 ) |
|
3990 { |
|
3991 Entry *root = rootNav->entry(); |
|
3992 //if (masterCd->visited) return; |
|
3993 masterCd->visited=TRUE; |
|
3994 // The base class could ofcouse also be a non-nested class |
|
3995 ArgumentList *formalArgs = masterCd->templateArguments(); |
|
3996 QListIterator<BaseInfo> bii(*root->extends); |
|
3997 BaseInfo *bi=0; |
|
3998 for (bii.toFirst();(bi=bii.current());++bii) |
|
3999 { |
|
4000 //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n", |
|
4001 // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1); |
|
4002 bool delTempNames=FALSE; |
|
4003 if (templateNames==0) |
|
4004 { |
|
4005 templateNames = getTemplateArgumentsInName(formalArgs,bi->name); |
|
4006 delTempNames=TRUE; |
|
4007 } |
|
4008 BaseInfo tbi(bi->name,bi->prot,bi->virt); |
|
4009 if (actualArgs) // substitute the formal template arguments of the base class |
|
4010 { |
|
4011 tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs); |
|
4012 } |
|
4013 //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data()); |
|
4014 |
|
4015 if (mode==DocumentedOnly) |
|
4016 { |
|
4017 // find a documented base class in the correct scope |
|
4018 if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial)) |
|
4019 { |
|
4020 if (!Config_getBool("HIDE_UNDOC_RELATIONS")) |
|
4021 { |
|
4022 // no documented base class -> try to find an undocumented one |
|
4023 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,isArtificial); |
|
4024 } |
|
4025 } |
|
4026 } |
|
4027 else if (mode==TemplateInstances) |
|
4028 { |
|
4029 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial); |
|
4030 } |
|
4031 if (delTempNames) |
|
4032 { |
|
4033 delete templateNames; |
|
4034 templateNames=0; |
|
4035 } |
|
4036 } |
|
4037 } |
|
4038 |
|
4039 //---------------------------------------------------------------------- |
|
4040 |
|
4041 static bool findTemplateInstanceRelation(Entry *root, |
|
4042 Definition *context, |
|
4043 ClassDef *templateClass,const QCString &templSpec, |
|
4044 QDict<int> *templateNames, |
|
4045 bool isArtificial) |
|
4046 { |
|
4047 Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n", |
|
4048 templateClass->name().data(),templSpec.data()); |
|
4049 //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=", |
|
4050 // templateClass->name().data(),templSpec.data()); |
|
4051 //if (templateNames) |
|
4052 //{ |
|
4053 // QDictIterator<int> qdi(*templateNames); |
|
4054 // int *tempArgIndex; |
|
4055 // for (;(tempArgIndex=qdi.current());++qdi) |
|
4056 // { |
|
4057 // printf("(%s->%d) ",qdi.currentKey().data(),*tempArgIndex); |
|
4058 // } |
|
4059 //} |
|
4060 //printf("\n"); |
|
4061 |
|
4062 bool existingClass = (templSpec == |
|
4063 tempArgListToString(templateClass->templateArguments()) |
|
4064 ); |
|
4065 if (existingClass) return TRUE; |
|
4066 |
|
4067 bool freshInstance=FALSE; |
|
4068 ClassDef *instanceClass = templateClass->insertTemplateInstance( |
|
4069 root->fileName,root->startLine,templSpec,freshInstance); |
|
4070 if (isArtificial) instanceClass->setArtificial(TRUE); |
|
4071 instanceClass->setIsObjectiveC(root->objc); |
|
4072 |
|
4073 if (freshInstance) |
|
4074 { |
|
4075 Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",instanceClass->name().data()); |
|
4076 Doxygen::classSDict->append(instanceClass->name(),instanceClass); |
|
4077 instanceClass->setTemplateBaseClassNames(templateNames); |
|
4078 |
|
4079 // search for new template instances caused by base classes of |
|
4080 // instanceClass |
|
4081 EntryNav *templateRootNav = g_classEntries.find(templateClass->name()); |
|
4082 if (templateRootNav) |
|
4083 { |
|
4084 bool unloadNeeded=FALSE; |
|
4085 Entry *templateRoot = templateRootNav->entry(); |
|
4086 if (templateRoot==0) // not yet loaded |
|
4087 { |
|
4088 templateRootNav->loadEntry(g_storage); |
|
4089 templateRoot = templateRootNav->entry(); |
|
4090 ASSERT(templateRoot!=0); // now it should really be loaded |
|
4091 unloadNeeded=TRUE; |
|
4092 } |
|
4093 |
|
4094 Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n", |
|
4095 templateRoot->name.data(),templSpec.data()); |
|
4096 ArgumentList *templArgs = new ArgumentList; |
|
4097 stringToArgumentList(templSpec,templArgs); |
|
4098 findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass, |
|
4099 TemplateInstances,isArtificial,templArgs,templateNames); |
|
4100 |
|
4101 findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass, |
|
4102 isArtificial,templArgs,templateNames); |
|
4103 delete templArgs; |
|
4104 |
|
4105 if (unloadNeeded) // still cleanup to do |
|
4106 { |
|
4107 templateRootNav->releaseEntry(); |
|
4108 } |
|
4109 } |
|
4110 else |
|
4111 { |
|
4112 Debug::print(Debug::Classes,0," no template root entry found!\n"); |
|
4113 // TODO: what happened if we get here? |
|
4114 } |
|
4115 |
|
4116 //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data()); |
|
4117 //ArgumentList *tl = templateClass->templateArguments(); |
|
4118 } |
|
4119 else |
|
4120 { |
|
4121 Debug::print(Debug::Classes,0," instance already exists!\n"); |
|
4122 } |
|
4123 return TRUE; |
|
4124 } |
|
4125 |
|
4126 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name) |
|
4127 { |
|
4128 QCString n=name; |
|
4129 int index=n.find('<'); |
|
4130 if (index!=-1) |
|
4131 { |
|
4132 n=n.left(index); |
|
4133 } |
|
4134 bool result = rightScopeMatch(scope,n); |
|
4135 return result; |
|
4136 } |
|
4137 |
|
4138 /*! Searches for the end of a template in prototype \a s starting from |
|
4139 * character position \a startPos. If the end was found the position |
|
4140 * of the closing \> is returned, otherwise -1 is returned. |
|
4141 * |
|
4142 * Handles exotic cases such as |
|
4143 * \code |
|
4144 * Class<(id<0)> |
|
4145 * Class<bits<<2> |
|
4146 * Class<"<"> |
|
4147 * Class<'<'> |
|
4148 * Class<(")<")> |
|
4149 * \endcode |
|
4150 */ |
|
4151 static int findEndOfTemplate(const QCString &s,int startPos) |
|
4152 { |
|
4153 // locate end of template |
|
4154 int e=startPos; |
|
4155 int brCount=1; |
|
4156 int roundCount=0; |
|
4157 int len = s.length(); |
|
4158 bool insideString=FALSE; |
|
4159 bool insideChar=FALSE; |
|
4160 char pc = 0; |
|
4161 while (e<len && brCount!=0) |
|
4162 { |
|
4163 char c=s.at(e); |
|
4164 switch(c) |
|
4165 { |
|
4166 case '<': |
|
4167 if (!insideString && !insideChar) |
|
4168 { |
|
4169 if (e<len-1 && s.at(e+1)=='<') |
|
4170 e++; |
|
4171 else if (roundCount==0) |
|
4172 brCount++; |
|
4173 } |
|
4174 break; |
|
4175 case '>': |
|
4176 if (!insideString && !insideChar) |
|
4177 { |
|
4178 if (e<len-1 && s.at(e+1)=='>') |
|
4179 e++; |
|
4180 else if (roundCount==0) |
|
4181 brCount--; |
|
4182 } |
|
4183 break; |
|
4184 case '(': |
|
4185 if (!insideString && !insideChar) |
|
4186 roundCount++; |
|
4187 break; |
|
4188 case ')': |
|
4189 if (!insideString && !insideChar) |
|
4190 roundCount--; |
|
4191 break; |
|
4192 case '"': |
|
4193 if (!insideChar) |
|
4194 { |
|
4195 if (insideString && pc!='\\') |
|
4196 insideString=FALSE; |
|
4197 else |
|
4198 insideString=TRUE; |
|
4199 } |
|
4200 break; |
|
4201 case '\'': |
|
4202 if (!insideString) |
|
4203 { |
|
4204 if (insideChar && pc!='\\') |
|
4205 insideChar=FALSE; |
|
4206 else |
|
4207 insideChar=TRUE; |
|
4208 } |
|
4209 break; |
|
4210 } |
|
4211 pc = c; |
|
4212 e++; |
|
4213 } |
|
4214 return brCount==0 ? e : -1; |
|
4215 } |
|
4216 |
|
4217 static bool findClassRelation( |
|
4218 EntryNav *rootNav, |
|
4219 Definition *context, |
|
4220 ClassDef *cd, |
|
4221 BaseInfo *bi, |
|
4222 QDict<int> *templateNames, |
|
4223 FindBaseClassRelation_Mode mode, |
|
4224 bool isArtificial |
|
4225 ) |
|
4226 { |
|
4227 //printf("findClassRelation(class=%s base=%s templateNames=", |
|
4228 // cd->name().data(),bi->name.data()); |
|
4229 //if (templateNames) |
|
4230 //{ |
|
4231 // QDictIterator<int> qdi(*templateNames); |
|
4232 // int *tempArgIndex; |
|
4233 // for (;(tempArgIndex=qdi.current());++qdi) |
|
4234 // { |
|
4235 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex); |
|
4236 // } |
|
4237 //} |
|
4238 //printf("\n"); |
|
4239 |
|
4240 Entry *root = rootNav->entry(); |
|
4241 |
|
4242 QCString biName=bi->name; |
|
4243 bool explicitGlobalScope=FALSE; |
|
4244 //printf("findClassRelation: biName=`%s'\n",biName.data()); |
|
4245 if (biName.left(2)=="::") // explicit global scope |
|
4246 { |
|
4247 biName=biName.right(biName.length()-2); |
|
4248 explicitGlobalScope=TRUE; |
|
4249 } |
|
4250 |
|
4251 EntryNav *parentNode=rootNav->parent(); |
|
4252 bool lastParent=FALSE; |
|
4253 do // for each parent scope, starting with the largest scope |
|
4254 // (in case of nested classes) |
|
4255 { |
|
4256 QCString scopeName= parentNode ? parentNode->name().data() : ""; |
|
4257 int scopeOffset=explicitGlobalScope ? 0 : scopeName.length(); |
|
4258 do // try all parent scope prefixes, starting with the largest scope |
|
4259 { |
|
4260 //printf("scopePrefix=`%s' biName=`%s'\n", |
|
4261 // scopeName.left(scopeOffset).data(),biName.data()); |
|
4262 |
|
4263 QCString baseClassName=biName; |
|
4264 if (scopeOffset>0) |
|
4265 { |
|
4266 baseClassName.prepend(scopeName.left(scopeOffset)+"::"); |
|
4267 } |
|
4268 //QCString stripped; |
|
4269 //baseClassName=stripTemplateSpecifiersFromScope |
|
4270 // (removeRedundantWhiteSpace(baseClassName),TRUE, |
|
4271 // &stripped); |
|
4272 MemberDef *baseClassTypeDef=0; |
|
4273 QCString templSpec; |
|
4274 ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context, |
|
4275 cd->getFileDef(), |
|
4276 baseClassName, |
|
4277 &baseClassTypeDef, |
|
4278 &templSpec, |
|
4279 mode==Undocumented, |
|
4280 TRUE |
|
4281 ); |
|
4282 //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n", |
|
4283 // baseClassName.data(),baseClass,cd,explicitGlobalScope); |
|
4284 //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n", |
|
4285 // cd ? cd->name().data():"<none>", |
|
4286 // baseClassName.data(), |
|
4287 // baseClass?baseClass->name().data():"<none>", |
|
4288 // templSpec.data() |
|
4289 // ); |
|
4290 //if (baseClassName.left(root->name.length())!=root->name || |
|
4291 // baseClassName.at(root->name.length())!='<' |
|
4292 // ) // Check for base class with the same name. |
|
4293 // // If found then look in the outer scope for a match |
|
4294 // // and prevent recursion. |
|
4295 if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope) |
|
4296 { |
|
4297 Debug::print( |
|
4298 Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n", |
|
4299 baseClassName.data(), |
|
4300 rootNav->name().data(), |
|
4301 (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"), |
|
4302 (bi->virt==Normal)?"normal":"virtual", |
|
4303 templSpec.data() |
|
4304 ); |
|
4305 |
|
4306 int i=baseClassName.find('<'); |
|
4307 int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i); |
|
4308 if (si==-1) si=0; |
|
4309 if (baseClass==0 && i!=-1) |
|
4310 // base class has template specifiers |
|
4311 { |
|
4312 // TODO: here we should try to find the correct template specialization |
|
4313 // but for now, we only look for the unspecializated base class. |
|
4314 int e=findEndOfTemplate(baseClassName,i+1); |
|
4315 //printf("baseClass==0 i=%d e=%d\n",i,e); |
|
4316 if (e!=-1) // end of template was found at e |
|
4317 { |
|
4318 templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i)); |
|
4319 baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e); |
|
4320 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context, |
|
4321 cd->getFileDef(), |
|
4322 baseClassName, |
|
4323 &baseClassTypeDef, |
|
4324 0, //&templSpec, |
|
4325 mode==Undocumented, |
|
4326 TRUE |
|
4327 ); |
|
4328 //printf("baseClass=%p -> baseClass=%s templSpec=%s\n", |
|
4329 // baseClass,baseClassName.data(),templSpec.data()); |
|
4330 } |
|
4331 } |
|
4332 else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also |
|
4333 // know it is a template, so see if |
|
4334 // we can also link to the explicit |
|
4335 // instance (for instance if a class |
|
4336 // derived from a template argument) |
|
4337 { |
|
4338 //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data()); |
|
4339 ClassDef *templClass=getClass(baseClass->name()+templSpec); |
|
4340 if (templClass) |
|
4341 { |
|
4342 // use the template instance instead of the template base. |
|
4343 baseClass = templClass; |
|
4344 templSpec.resize(0); |
|
4345 } |
|
4346 } |
|
4347 |
|
4348 //printf("cd=%p baseClass=%p\n",cd,baseClass); |
|
4349 bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances); |
|
4350 //printf("1. found=%d\n",found); |
|
4351 if (!found && si!=-1) |
|
4352 { |
|
4353 QCString tmpTemplSpec; |
|
4354 // replace any namespace aliases |
|
4355 replaceNamespaceAliases(baseClassName,si); |
|
4356 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context, |
|
4357 cd->getFileDef(), |
|
4358 baseClassName, |
|
4359 &baseClassTypeDef, |
|
4360 &tmpTemplSpec, |
|
4361 mode==Undocumented, |
|
4362 TRUE |
|
4363 ); |
|
4364 found=baseClass!=0 && baseClass!=cd; |
|
4365 if (found) templSpec = tmpTemplSpec; |
|
4366 } |
|
4367 //printf("2. found=%d\n",found); |
|
4368 |
|
4369 //printf("root->name=%s biName=%s baseClassName=%s\n", |
|
4370 // root->name.data(),biName.data(),baseClassName.data()); |
|
4371 |
|
4372 if (!found) |
|
4373 { |
|
4374 baseClass=findClassWithinClassContext(context,cd,baseClassName); |
|
4375 //printf("findClassWithinClassContext(%s,%s)=%p\n", |
|
4376 // cd->name().data(),baseClassName.data(),baseClass); |
|
4377 found = baseClass!=0 && baseClass!=cd; |
|
4378 |
|
4379 } |
|
4380 bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0; |
|
4381 // make templSpec canonical |
|
4382 // Warning: the following line doesn't work for Mixin classes (see bug 560623) |
|
4383 // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec); |
|
4384 |
|
4385 //printf("3. found=%d\n",found); |
|
4386 if (found) |
|
4387 { |
|
4388 Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data()); |
|
4389 // add base class to this class |
|
4390 |
|
4391 // if templSpec is not empty then we should "instantiate" |
|
4392 // the template baseClass. A new ClassDef should be created |
|
4393 // to represent the instance. To be able to add the (instantiated) |
|
4394 // members and documentation of a template class |
|
4395 // (inserted in that template class at a later stage), |
|
4396 // the template should know about its instances. |
|
4397 // the instantiation process, should be done in a recursive way, |
|
4398 // since instantiating a template may introduce new inheritance |
|
4399 // relations. |
|
4400 if (!templSpec.isEmpty() && mode==TemplateInstances) |
|
4401 { |
|
4402 // if baseClass is actually a typedef then we should not |
|
4403 // instantiate it, since typedefs are in a different namespace |
|
4404 // see bug531637 for an example where this would otherwise hang |
|
4405 // doxygen |
|
4406 if (baseClassTypeDef==0) |
|
4407 { |
|
4408 //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef); |
|
4409 findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial); |
|
4410 } |
|
4411 } |
|
4412 else if (mode==DocumentedOnly || mode==Undocumented) |
|
4413 { |
|
4414 //printf(" => insert base class\n"); |
|
4415 QCString usedName; |
|
4416 if (baseClassTypeDef) |
|
4417 { |
|
4418 usedName=biName; |
|
4419 //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data()); |
|
4420 } |
|
4421 if (Config_getBool("SIP_SUPPORT")) bi->prot=Public; |
|
4422 cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec); |
|
4423 // add this class as super class to the base class |
|
4424 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec); |
|
4425 } |
|
4426 return TRUE; |
|
4427 } |
|
4428 else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument)) |
|
4429 { |
|
4430 Debug::print(Debug::Classes,0, |
|
4431 " New undocumented base class `%s' baseClassName=%s\n", |
|
4432 biName.data(),baseClassName.data() |
|
4433 ); |
|
4434 baseClass=0; |
|
4435 if (isATemplateArgument) |
|
4436 { |
|
4437 baseClass=Doxygen::hiddenClasses->find(baseClassName); |
|
4438 if (baseClass==0) |
|
4439 { |
|
4440 baseClass=new ClassDef(root->fileName,root->startLine, |
|
4441 baseClassName,ClassDef::Class); |
|
4442 Doxygen::hiddenClasses->append(baseClassName,baseClass); |
|
4443 if (isArtificial) baseClass->setArtificial(TRUE); |
|
4444 } |
|
4445 } |
|
4446 else |
|
4447 { |
|
4448 baseClass=Doxygen::classSDict->find(baseClassName); |
|
4449 //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n", |
|
4450 // baseClassName.data(),baseClass,biName.data(),templSpec.data()); |
|
4451 if (baseClass==0) |
|
4452 { |
|
4453 baseClass=new ClassDef(root->fileName,root->startLine, |
|
4454 baseClassName,ClassDef::Class); |
|
4455 Doxygen::classSDict->append(baseClassName,baseClass); |
|
4456 if (isArtificial) baseClass->setArtificial(TRUE); |
|
4457 } |
|
4458 } |
|
4459 // add base class to this class |
|
4460 cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec); |
|
4461 // add this class as super class to the base class |
|
4462 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec); |
|
4463 // the undocumented base was found in this file |
|
4464 baseClass->insertUsedFile(root->fileName); |
|
4465 baseClass->setOuterScope(Doxygen::globalScope); |
|
4466 return TRUE; |
|
4467 } |
|
4468 else |
|
4469 { |
|
4470 Debug::print(Debug::Classes,0," Base class `%s' not found\n",biName.data()); |
|
4471 } |
|
4472 } |
|
4473 else |
|
4474 { |
|
4475 if (mode!=TemplateInstances) |
|
4476 { |
|
4477 warn(root->fileName,root->startLine, |
|
4478 "Detected potential recursive class relation " |
|
4479 "between class %s and base class %s!\n", |
|
4480 root->name.data(),baseClassName.data() |
|
4481 ); |
|
4482 } |
|
4483 // for mode==TemplateInstance this case is quite common and |
|
4484 // indicates a relation between a template class and a template |
|
4485 // instance with the same name. |
|
4486 } |
|
4487 if (scopeOffset==0) |
|
4488 { |
|
4489 scopeOffset=-1; |
|
4490 } |
|
4491 else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1) |
|
4492 { |
|
4493 scopeOffset=0; |
|
4494 } |
|
4495 //printf("new scopeOffset=`%d'",scopeOffset); |
|
4496 } while (scopeOffset>=0); |
|
4497 |
|
4498 if (parentNode==0) |
|
4499 { |
|
4500 lastParent=TRUE; |
|
4501 } |
|
4502 else |
|
4503 { |
|
4504 parentNode=parentNode->parent(); |
|
4505 } |
|
4506 } while (lastParent); |
|
4507 |
|
4508 return FALSE; |
|
4509 } |
|
4510 |
|
4511 //---------------------------------------------------------------------- |
|
4512 // Computes the base and super classes for each class in the tree |
|
4513 |
|
4514 static bool isClassSection(EntryNav *rootNav) |
|
4515 { |
|
4516 if ( !rootNav->name().isEmpty() ) |
|
4517 { |
|
4518 if (rootNav->section() & Entry::COMPOUND_MASK) |
|
4519 // is it a compound (class, struct, union, interface ...) |
|
4520 { |
|
4521 return TRUE; |
|
4522 } |
|
4523 else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) |
|
4524 // is it a documentation block with inheritance info. |
|
4525 { |
|
4526 rootNav->loadEntry(g_storage); |
|
4527 Entry *root = rootNav->entry(); |
|
4528 bool extends = root->extends->count()>0; |
|
4529 rootNav->releaseEntry(); |
|
4530 if (extends) return TRUE; |
|
4531 } |
|
4532 } |
|
4533 return FALSE; |
|
4534 } |
|
4535 |
|
4536 |
|
4537 /*! Builds a dictionary of all entry nodes in the tree starting with \a root |
|
4538 */ |
|
4539 static void findClassEntries(EntryNav *rootNav) |
|
4540 { |
|
4541 if (isClassSection(rootNav)) |
|
4542 { |
|
4543 g_classEntries.insert(rootNav->name(),rootNav); |
|
4544 } |
|
4545 RECURSE_ENTRYTREE(findClassEntries,rootNav); |
|
4546 } |
|
4547 |
|
4548 /*! Using the dictionary build by findClassEntries(), this |
|
4549 * function will look for additional template specialization that |
|
4550 * exists as inheritance relations only. These instances will be |
|
4551 * added to the template they are derived from. |
|
4552 */ |
|
4553 static void findInheritedTemplateInstances() |
|
4554 { |
|
4555 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
4556 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; |
|
4557 QDictIterator<EntryNav> edi(g_classEntries); |
|
4558 EntryNav *rootNav; |
|
4559 for (;(rootNav=edi.current());++edi) |
|
4560 { |
|
4561 ClassDef *cd; |
|
4562 // strip any annonymous scopes first |
|
4563 QCString bName=stripAnonymousNamespaceScope(rootNav->name()); |
|
4564 bName=stripTemplateSpecifiersFromScope(bName); |
|
4565 Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",bName.data()); |
|
4566 if ((cd=getClass(bName))) |
|
4567 { |
|
4568 rootNav->loadEntry(g_storage); |
|
4569 //printf("Class %s %d\n",cd->name().data(),root->extends->count()); |
|
4570 findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE); |
|
4571 rootNav->releaseEntry(); |
|
4572 } |
|
4573 } |
|
4574 } |
|
4575 |
|
4576 static void findUsedTemplateInstances() |
|
4577 { |
|
4578 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
4579 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; |
|
4580 QDictIterator<EntryNav> edi(g_classEntries); |
|
4581 EntryNav *rootNav; |
|
4582 for (;(rootNav=edi.current());++edi) |
|
4583 { |
|
4584 ClassDef *cd; |
|
4585 // strip any annonymous scopes first |
|
4586 QCString bName=stripAnonymousNamespaceScope(rootNav->name()); |
|
4587 bName=stripTemplateSpecifiersFromScope(bName); |
|
4588 Debug::print(Debug::Classes,0," Usage: Class %s : \n",bName.data()); |
|
4589 if ((cd=getClass(bName))) |
|
4590 { |
|
4591 rootNav->loadEntry(g_storage); |
|
4592 findUsedClassesForClass(rootNav,cd,cd,cd,TRUE); |
|
4593 rootNav->releaseEntry(); |
|
4594 } |
|
4595 } |
|
4596 } |
|
4597 |
|
4598 static void computeClassRelations() |
|
4599 { |
|
4600 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
4601 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE; |
|
4602 QDictIterator<EntryNav> edi(g_classEntries); |
|
4603 EntryNav *rootNav; |
|
4604 for (;(rootNav=edi.current());++edi) |
|
4605 { |
|
4606 ClassDef *cd; |
|
4607 |
|
4608 rootNav->loadEntry(g_storage); |
|
4609 Entry *root = rootNav->entry(); |
|
4610 |
|
4611 // strip any annonymous scopes first |
|
4612 QCString bName=stripAnonymousNamespaceScope(rootNav->name()); |
|
4613 bName=stripTemplateSpecifiersFromScope(bName); |
|
4614 Debug::print(Debug::Classes,0," Relations: Class %s : \n",bName.data()); |
|
4615 if ((cd=getClass(bName))) |
|
4616 { |
|
4617 findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE); |
|
4618 } |
|
4619 if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && |
|
4620 bName.right(2)!="::") |
|
4621 { |
|
4622 if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name |
|
4623 (guessSection(root->fileName)==Entry::HEADER_SEC || |
|
4624 Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file |
|
4625 (root->protection!=Private || Config_getBool("EXTRACT_PRIVATE")) && // hidden by protection |
|
4626 !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible |
|
4627 ) |
|
4628 warn_undoc( |
|
4629 root->fileName,root->startLine, |
|
4630 "Warning: Compound %s is not documented.", |
|
4631 root->name.data() |
|
4632 ); |
|
4633 } |
|
4634 |
|
4635 rootNav->releaseEntry(); |
|
4636 } |
|
4637 } |
|
4638 |
|
4639 static void computeTemplateClassRelations() |
|
4640 { |
|
4641 QDictIterator<EntryNav> edi(g_classEntries); |
|
4642 EntryNav *rootNav; |
|
4643 for (;(rootNav=edi.current());++edi) |
|
4644 { |
|
4645 rootNav->loadEntry(g_storage); |
|
4646 Entry *root = rootNav->entry(); |
|
4647 |
|
4648 QCString bName=stripAnonymousNamespaceScope(root->name); |
|
4649 bName=stripTemplateSpecifiersFromScope(bName); |
|
4650 ClassDef *cd=getClass(bName); |
|
4651 // strip any annonymous scopes first |
|
4652 QDict<ClassDef> *templInstances = 0; |
|
4653 if (cd && (templInstances=cd->getTemplateInstances())) |
|
4654 { |
|
4655 Debug::print(Debug::Classes,0," Template class %s : \n",cd->name().data()); |
|
4656 QDictIterator<ClassDef> tdi(*templInstances); |
|
4657 ClassDef *tcd; |
|
4658 for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance |
|
4659 { |
|
4660 Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data()); |
|
4661 QCString templSpec = tdi.currentKey(); |
|
4662 ArgumentList *templArgs = new ArgumentList; |
|
4663 stringToArgumentList(templSpec,templArgs); |
|
4664 QList<BaseInfo> *baseList=root->extends; |
|
4665 BaseInfo *bi=baseList->first(); |
|
4666 while (bi) // for each base class of the template |
|
4667 { |
|
4668 // check if the base class is a template argument |
|
4669 BaseInfo tbi(bi->name,bi->prot,bi->virt); |
|
4670 ArgumentList *tl = cd->templateArguments(); |
|
4671 if (tl) |
|
4672 { |
|
4673 QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames(); |
|
4674 QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name); |
|
4675 // for each template name that we inherit from we need to |
|
4676 // substitute the formal with the actual arguments |
|
4677 QDict<int> *actualTemplateNames = new QDict<int>(17); |
|
4678 actualTemplateNames->setAutoDelete(TRUE); |
|
4679 QDictIterator<int> qdi(*templateNames); |
|
4680 for (qdi.toFirst();qdi.current();++qdi) |
|
4681 { |
|
4682 int templIndex = *qdi.current(); |
|
4683 Argument *actArg = 0; |
|
4684 if (templIndex<(int)templArgs->count()) |
|
4685 { |
|
4686 actArg=templArgs->at(templIndex); |
|
4687 } |
|
4688 if (actArg!=0 && |
|
4689 baseClassNames!=0 && |
|
4690 baseClassNames->find(actArg->type)!=0 && |
|
4691 actualTemplateNames->find(actArg->type)==0 |
|
4692 ) |
|
4693 { |
|
4694 actualTemplateNames->insert(actArg->type,new int(templIndex)); |
|
4695 } |
|
4696 } |
|
4697 delete templateNames; |
|
4698 |
|
4699 tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs); |
|
4700 // find a documented base class in the correct scope |
|
4701 if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE)) |
|
4702 { |
|
4703 // no documented base class -> try to find an undocumented one |
|
4704 findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE); |
|
4705 } |
|
4706 delete actualTemplateNames; |
|
4707 } |
|
4708 bi=baseList->next(); |
|
4709 } |
|
4710 delete templArgs; |
|
4711 } // class has no base classes |
|
4712 } |
|
4713 |
|
4714 rootNav->releaseEntry(); |
|
4715 } |
|
4716 } |
|
4717 |
|
4718 //----------------------------------------------------------------------- |
|
4719 // compute the references (anchors in HTML) for each function in the file |
|
4720 |
|
4721 static void computeMemberReferences() |
|
4722 { |
|
4723 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
4724 ClassDef *cd=0; |
|
4725 for (cli.toFirst();(cd=cli.current());++cli) |
|
4726 { |
|
4727 cd->computeAnchors(); |
|
4728 } |
|
4729 FileName *fn=Doxygen::inputNameList->first(); |
|
4730 while (fn) |
|
4731 { |
|
4732 FileDef *fd=fn->first(); |
|
4733 while (fd) |
|
4734 { |
|
4735 fd->computeAnchors(); |
|
4736 fd=fn->next(); |
|
4737 } |
|
4738 fn=Doxygen::inputNameList->next(); |
|
4739 } |
|
4740 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); |
|
4741 NamespaceDef *nd=0; |
|
4742 for (nli.toFirst();(nd=nli.current());++nli) |
|
4743 { |
|
4744 nd->computeAnchors(); |
|
4745 } |
|
4746 GroupSDict::Iterator gli(*Doxygen::groupSDict); |
|
4747 GroupDef *gd; |
|
4748 for (gli.toFirst();(gd=gli.current());++gli) |
|
4749 { |
|
4750 gd->computeAnchors(); |
|
4751 } |
|
4752 } |
|
4753 |
|
4754 //---------------------------------------------------------------------- |
|
4755 |
|
4756 static void addListReferences() |
|
4757 { |
|
4758 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); |
|
4759 MemberName *mn=0; |
|
4760 for (mnli.toFirst();(mn=mnli.current());++mnli) |
|
4761 { |
|
4762 MemberNameIterator mni(*mn); |
|
4763 MemberDef *md=0; |
|
4764 for (mni.toFirst();(md=mni.current());++mni) |
|
4765 { |
|
4766 md->visited=FALSE; |
|
4767 } |
|
4768 } |
|
4769 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); |
|
4770 for (fnli.toFirst();(mn=fnli.current());++fnli) |
|
4771 { |
|
4772 MemberNameIterator mni(*mn); |
|
4773 MemberDef *md=0; |
|
4774 for (mni.toFirst();(md=mni.current());++mni) |
|
4775 { |
|
4776 md->visited=FALSE; |
|
4777 } |
|
4778 } |
|
4779 |
|
4780 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
4781 ClassDef *cd=0; |
|
4782 for (cli.toFirst();(cd=cli.current());++cli) |
|
4783 { |
|
4784 cd->addListReferences(); |
|
4785 } |
|
4786 FileName *fn=Doxygen::inputNameList->first(); |
|
4787 while (fn) |
|
4788 { |
|
4789 FileDef *fd=fn->first(); |
|
4790 while (fd) |
|
4791 { |
|
4792 fd->addListReferences(); |
|
4793 fd=fn->next(); |
|
4794 } |
|
4795 fn=Doxygen::inputNameList->next(); |
|
4796 } |
|
4797 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); |
|
4798 NamespaceDef *nd=0; |
|
4799 for (nli.toFirst();(nd=nli.current());++nli) |
|
4800 { |
|
4801 nd->addListReferences(); |
|
4802 } |
|
4803 GroupSDict::Iterator gli(*Doxygen::groupSDict); |
|
4804 GroupDef *gd; |
|
4805 for (gli.toFirst();(gd=gli.current());++gli) |
|
4806 { |
|
4807 gd->addListReferences(); |
|
4808 } |
|
4809 PageSDict::Iterator pdi(*Doxygen::pageSDict); |
|
4810 PageDef *pd=0; |
|
4811 for (pdi.toFirst();(pd=pdi.current());++pdi) |
|
4812 { |
|
4813 QCString name = pd->name(); |
|
4814 if (pd->getGroupDef()) |
|
4815 { |
|
4816 name = pd->getGroupDef()->getOutputFileBase(); |
|
4817 } |
|
4818 { |
|
4819 LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems(); |
|
4820 addRefItem(xrefItems.pointer(), |
|
4821 name, |
|
4822 theTranslator->trPage(TRUE,TRUE), |
|
4823 name,pd->title(),0); |
|
4824 } |
|
4825 } |
|
4826 DirSDict::Iterator ddi(*Doxygen::directories); |
|
4827 DirDef *dd = 0; |
|
4828 for (ddi.toFirst();(dd=ddi.current());++ddi) |
|
4829 { |
|
4830 QCString name = dd->getOutputFileBase(); |
|
4831 //if (dd->getGroupDef()) |
|
4832 //{ |
|
4833 // name = dd->getGroupDef()->getOutputFileBase(); |
|
4834 //} |
|
4835 LockingPtr< QList<ListItemInfo> > xrefItems = dd->xrefListItems(); |
|
4836 addRefItem(xrefItems.pointer(), |
|
4837 name, |
|
4838 theTranslator->trDir(TRUE,TRUE), |
|
4839 name,dd->displayName(),0); |
|
4840 } |
|
4841 } |
|
4842 |
|
4843 //---------------------------------------------------------------------- |
|
4844 |
|
4845 static void generateXRefPages() |
|
4846 { |
|
4847 QDictIterator<RefList> di(*Doxygen::xrefLists); |
|
4848 RefList *rl; |
|
4849 for (di.toFirst();(rl=di.current());++di) |
|
4850 { |
|
4851 rl->generatePage(); |
|
4852 } |
|
4853 } |
|
4854 |
|
4855 //---------------------------------------------------------------------- |
|
4856 // Copy the documentation in entry `root' to member definition `md' and |
|
4857 // set the function declaration of the member to `funcDecl'. If the boolean |
|
4858 // over_load is set the standard overload text is added. |
|
4859 |
|
4860 static void addMemberDocs(EntryNav *rootNav, |
|
4861 MemberDef *md, const char *funcDecl, |
|
4862 ArgumentList *al, |
|
4863 bool over_load, |
|
4864 NamespaceSDict * |
|
4865 ) |
|
4866 { |
|
4867 Entry *root = rootNav->entry(); |
|
4868 //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n", |
|
4869 // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec); |
|
4870 QCString fDecl=funcDecl; |
|
4871 // strip extern specifier |
|
4872 fDecl.stripPrefix("extern "); |
|
4873 md->setDefinition(fDecl); |
|
4874 md->enableCallGraph(root->callGraph); |
|
4875 md->enableCallerGraph(root->callerGraph); |
|
4876 ClassDef *cd=md->getClassDef(); |
|
4877 NamespaceDef *nd=md->getNamespaceDef(); |
|
4878 QCString fullName; |
|
4879 if (cd) |
|
4880 fullName = cd->name(); |
|
4881 else if (nd) |
|
4882 fullName = nd->name(); |
|
4883 |
|
4884 if (!fullName.isEmpty()) fullName+="::"; |
|
4885 fullName+=md->name(); |
|
4886 FileDef *rfd=rootNav->fileDef(); |
|
4887 |
|
4888 // TODO determine scope based on root not md |
|
4889 Definition *rscope = md->getOuterScope(); |
|
4890 |
|
4891 LockingPtr<ArgumentList> mdAl = md->argumentList(); |
|
4892 if (al) |
|
4893 { |
|
4894 //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty()); |
|
4895 mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty()); |
|
4896 } |
|
4897 else |
|
4898 { |
|
4899 if ( |
|
4900 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(), |
|
4901 rscope,rfd,root->argList, |
|
4902 TRUE |
|
4903 ) |
|
4904 ) |
|
4905 { |
|
4906 //printf("merging arguments (2)\n"); |
|
4907 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty()); |
|
4908 } |
|
4909 } |
|
4910 if (over_load) // the \overload keyword was used |
|
4911 { |
|
4912 QCString doc=getOverloadDocs(); |
|
4913 if (!root->doc.isEmpty()) |
|
4914 { |
|
4915 doc+="<p>"; |
|
4916 doc+=root->doc; |
|
4917 } |
|
4918 md->setDocumentation(doc,root->docFile,root->docLine); |
|
4919 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
4920 md->setDocsForDefinition(!root->proto); |
|
4921 } |
|
4922 else |
|
4923 { |
|
4924 //printf("overwrite!\n"); |
|
4925 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
4926 md->setDocsForDefinition(!root->proto); |
|
4927 |
|
4928 //printf("overwrite!\n"); |
|
4929 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
4930 |
|
4931 if ( |
|
4932 (md->inbodyDocumentation().isEmpty() || |
|
4933 !rootNav->parent()->name().isEmpty() |
|
4934 ) && !root->inbodyDocs.isEmpty() |
|
4935 ) |
|
4936 { |
|
4937 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
4938 } |
|
4939 } |
|
4940 |
|
4941 //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n", |
|
4942 // md->initializer().data(),md->initializer().isEmpty(), |
|
4943 // root->initializer.data(),root->initializer.isEmpty() |
|
4944 // ); |
|
4945 if (md->initializer().isEmpty() && !root->initializer.isEmpty()) |
|
4946 { |
|
4947 //printf("setInitializer\n"); |
|
4948 md->setInitializer(root->initializer); |
|
4949 } |
|
4950 |
|
4951 md->setMaxInitLines(root->initLines); |
|
4952 |
|
4953 if (rfd) |
|
4954 { |
|
4955 if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) |
|
4956 ) |
|
4957 { |
|
4958 //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine); |
|
4959 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
4960 md->setBodyDef(rfd); |
|
4961 } |
|
4962 |
|
4963 md->setRefItems(root->sli); |
|
4964 } |
|
4965 |
|
4966 md->enableCallGraph(md->hasCallGraph() || root->callGraph); |
|
4967 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph); |
|
4968 |
|
4969 md->mergeMemberSpecifiers(root->spec); |
|
4970 md->addSectionsToDefinition(root->anchors); |
|
4971 addMemberToGroups(root,md); |
|
4972 if (cd) cd->insertUsedFile(root->fileName); |
|
4973 //printf("root->mGrpId=%d\n",root->mGrpId); |
|
4974 if (root->mGrpId!=-1) |
|
4975 { |
|
4976 if (md->getMemberGroupId()!=-1) |
|
4977 { |
|
4978 if (md->getMemberGroupId()!=root->mGrpId) |
|
4979 { |
|
4980 warn( |
|
4981 root->fileName,root->startLine, |
|
4982 "Warning: member %s belongs to two different groups. The second " |
|
4983 "one found here will be ignored.", |
|
4984 md->name().data() |
|
4985 ); |
|
4986 } |
|
4987 } |
|
4988 else // set group id |
|
4989 { |
|
4990 //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data()); |
|
4991 md->setMemberGroupId(root->mGrpId); |
|
4992 } |
|
4993 } |
|
4994 } |
|
4995 |
|
4996 //---------------------------------------------------------------------- |
|
4997 // find a class definition given the scope name and (optionally) a |
|
4998 // template list specifier |
|
4999 |
|
5000 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd, |
|
5001 const char *scopeName) |
|
5002 { |
|
5003 ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE); |
|
5004 return tcd; |
|
5005 } |
|
5006 |
|
5007 |
|
5008 //---------------------------------------------------------------------- |
|
5009 // Adds the documentation contained in `root' to a global function |
|
5010 // with name `name' and argument list `args' (for overloading) and |
|
5011 // function declaration `decl' to the corresponding member definition. |
|
5012 |
|
5013 static bool findGlobalMember(EntryNav *rootNav, |
|
5014 const QCString &namespaceName, |
|
5015 const char *name, |
|
5016 const char *tempArg, |
|
5017 const char *, |
|
5018 const char *decl) |
|
5019 { |
|
5020 Entry *root = rootNav->entry(); |
|
5021 Debug::print(Debug::FindMembers,0, |
|
5022 "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n", |
|
5023 namespaceName.data(),name,tempArg,decl); |
|
5024 QCString n=name; |
|
5025 if (n.isEmpty()) return FALSE; |
|
5026 if (n.find("::")!=-1) return FALSE; // skip undefined class members |
|
5027 MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary |
|
5028 if (mn==0) |
|
5029 { |
|
5030 mn=Doxygen::functionNameSDict->find(n); // try without template arguments |
|
5031 } |
|
5032 if (mn) // function name defined |
|
5033 { |
|
5034 Debug::print(Debug::FindMembers,0,"3. Found function scope\n"); |
|
5035 //int count=0; |
|
5036 MemberNameIterator mni(*mn); |
|
5037 MemberDef *md; |
|
5038 bool found=FALSE; |
|
5039 for (mni.toFirst();(md=mni.current()) && !found;++mni) |
|
5040 { |
|
5041 NamespaceDef *nd=md->getNamespaceDef(); |
|
5042 |
|
5043 //printf("Namespace namespaceName=%s nd=%s\n", |
|
5044 // namespaceName.data(),nd ? nd->name().data() : "<none>"); |
|
5045 |
|
5046 FileDef *fd=rootNav->fileDef(); |
|
5047 //printf("File %s\n",fd ? fd->name().data() : "<none>"); |
|
5048 NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0; |
|
5049 //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0; |
|
5050 //printf("NamespaceList %p\n",nl); |
|
5051 |
|
5052 // search in the list of namespaces that are imported via a |
|
5053 // using declaration |
|
5054 bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0; |
|
5055 |
|
5056 if ((namespaceName.isEmpty() && nd==0) || // not in a namespace |
|
5057 (nd && nd->name()==namespaceName) || // or in the same namespace |
|
5058 viaUsingDirective // member in `using' namespace |
|
5059 ) |
|
5060 { |
|
5061 Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n", |
|
5062 md->name().data(),namespaceName.data()); |
|
5063 QCString nsName = nd ? nd->name().data() : ""; |
|
5064 |
|
5065 NamespaceDef *rnd = 0; |
|
5066 if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName); |
|
5067 |
|
5068 LockingPtr<ArgumentList> mdAl = md->argumentList(); |
|
5069 bool matching= |
|
5070 (mdAl==0 && root->argList->count()==0) || |
|
5071 md->isVariable() || md->isTypedef() || /* in case of function pointers */ |
|
5072 matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(), |
|
5073 rnd ? rnd : Doxygen::globalScope,fd,root->argList, |
|
5074 FALSE); |
|
5075 |
|
5076 // for template members we need to check if the number of |
|
5077 // template arguments is the same, otherwise we are dealing with |
|
5078 // different functions. |
|
5079 if (matching && root->tArgLists) |
|
5080 { |
|
5081 LockingPtr<ArgumentList> mdTempl = md->templateArguments(); |
|
5082 if (mdTempl!=0) |
|
5083 { |
|
5084 if (root->tArgLists->getLast()->count()!=mdTempl->count()) |
|
5085 { |
|
5086 matching=FALSE; |
|
5087 } |
|
5088 } |
|
5089 } |
|
5090 |
|
5091 |
|
5092 //printf("%s<->%s\n", |
|
5093 // argListToString(md->argumentList()).data(), |
|
5094 // argListToString(root->argList).data()); |
|
5095 |
|
5096 // for static members we also check if the comment block was found in |
|
5097 // the same file. This is needed because static members with the same |
|
5098 // name can be in different files. Thus it would be wrong to just |
|
5099 // put the comment block at the first syntactically matching member. |
|
5100 if (matching && md->isStatic() && |
|
5101 md->getDefFileName()!=root->fileName && |
|
5102 mn->count()>1) |
|
5103 { |
|
5104 matching = FALSE; |
|
5105 } |
|
5106 |
|
5107 if (matching) // add docs to the member |
|
5108 { |
|
5109 Debug::print(Debug::FindMembers,0,"5. Match found\n"); |
|
5110 addMemberDocs(rootNav,md,decl,root->argList,FALSE); |
|
5111 found=TRUE; |
|
5112 } |
|
5113 } |
|
5114 } |
|
5115 if (!found && root->relatesType != Duplicate) // no match |
|
5116 { |
|
5117 QCString fullFuncDecl=decl; |
|
5118 if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE); |
|
5119 warn(root->fileName,root->startLine, |
|
5120 "Warning: no matching file member found for \n%s",fullFuncDecl.data()); |
|
5121 if (mn->count()>0) |
|
5122 { |
|
5123 warn_cont("Possible candidates:\n"); |
|
5124 for (mni.toFirst();(md=mni.current());++mni) |
|
5125 { |
|
5126 warn_cont(" %s\n",md->declaration()); |
|
5127 } |
|
5128 } |
|
5129 } |
|
5130 } |
|
5131 else // got docs for an undefined member! |
|
5132 { |
|
5133 if (root->type!="friend class" && |
|
5134 root->type!="friend struct" && |
|
5135 root->type!="friend union" && |
|
5136 (!Config_getBool("TYPEDEF_HIDES_STRUCT") || |
|
5137 root->type.find("typedef ")==-1) |
|
5138 ) |
|
5139 { |
|
5140 warn(root->fileName,root->startLine, |
|
5141 "Warning: documented function `%s' was not declared or defined.",decl |
|
5142 ); |
|
5143 } |
|
5144 } |
|
5145 return TRUE; |
|
5146 } |
|
5147 |
|
5148 static bool isSpecialization( |
|
5149 const QList<ArgumentList> &srcTempArgLists, |
|
5150 const QList<ArgumentList> &dstTempArgLists |
|
5151 ) |
|
5152 { |
|
5153 QListIterator<ArgumentList> srclali(srcTempArgLists); |
|
5154 QListIterator<ArgumentList> dstlali(dstTempArgLists); |
|
5155 for (;srclali.current();++srclali,++dstlali) |
|
5156 { |
|
5157 ArgumentList *sal = srclali.current(); |
|
5158 ArgumentList *dal = dstlali.current(); |
|
5159 if (!(sal && dal && sal->count()==dal->count())) return TRUE; |
|
5160 } |
|
5161 return FALSE; |
|
5162 } |
|
5163 |
|
5164 |
|
5165 static QCString substituteTemplatesInString( |
|
5166 const QList<ArgumentList> &srcTempArgLists, |
|
5167 const QList<ArgumentList> &dstTempArgLists, |
|
5168 ArgumentList *funcTempArgList, // can be used to match template specializations |
|
5169 const QCString &src |
|
5170 ) |
|
5171 { |
|
5172 QCString dst; |
|
5173 QRegExp re( "[A-Za-z_][A-Za-z_0-9]*"); |
|
5174 //printf("type=%s\n",sa->type.data()); |
|
5175 int i,p=0,l; |
|
5176 while ((i=re.match(src,p,&l))!=-1) // for each word in srcType |
|
5177 { |
|
5178 bool found=FALSE; |
|
5179 dst+=src.mid(p,i-p); |
|
5180 QCString name=src.mid(i,l); |
|
5181 |
|
5182 QListIterator<ArgumentList> srclali(srcTempArgLists); |
|
5183 QListIterator<ArgumentList> dstlali(dstTempArgLists); |
|
5184 for (;srclali.current() && !found;++srclali,++dstlali) |
|
5185 { |
|
5186 ArgumentListIterator tsali(*srclali.current()); |
|
5187 ArgumentListIterator tdali(*dstlali.current()); |
|
5188 Argument *tsa =0,*tda=0, *fa=0; |
|
5189 if (funcTempArgList) |
|
5190 { |
|
5191 fa=funcTempArgList->first(); |
|
5192 } |
|
5193 |
|
5194 for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali) |
|
5195 { |
|
5196 tda = tdali.current(); |
|
5197 //if (tda) printf("tsa=%s|%s tda=%s|%s\n", |
|
5198 // tsa->type.data(),tsa->name.data(), |
|
5199 // tda->type.data(),tda->name.data()); |
|
5200 if (name==tsa->name) |
|
5201 { |
|
5202 if (tda && tda->name.isEmpty()) |
|
5203 { |
|
5204 int vc=0; |
|
5205 if (tda->type.left(6)=="class ") vc=6; |
|
5206 else if (tda->type.left(9)=="typename ") vc=9; |
|
5207 if (vc>0) // convert type=="class T" to type=="class" name=="T" |
|
5208 { |
|
5209 tda->name = tda->type.mid(vc); |
|
5210 tda->type = tda->type.left(vc-1); |
|
5211 } |
|
5212 } |
|
5213 if (tda && !tda->name.isEmpty()) |
|
5214 { |
|
5215 name=tda->name; // substitute |
|
5216 found=TRUE; |
|
5217 } |
|
5218 else if (fa) |
|
5219 { |
|
5220 name=fa->type; |
|
5221 found=TRUE; |
|
5222 } |
|
5223 } |
|
5224 if (tda) |
|
5225 ++tdali; |
|
5226 else if (fa) |
|
5227 fa=funcTempArgList->next(); |
|
5228 } |
|
5229 //printf(" srcList='%s' dstList='%s faList='%s'\n", |
|
5230 // argListToString(srclali.current()).data(), |
|
5231 // argListToString(dstlali.current()).data(), |
|
5232 // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>"); |
|
5233 } |
|
5234 dst+=name; |
|
5235 p=i+l; |
|
5236 } |
|
5237 dst+=src.right(src.length()-p); |
|
5238 //printf(" substituteTemplatesInString(%s)=%s\n", |
|
5239 // src.data(),dst.data()); |
|
5240 return dst; |
|
5241 } |
|
5242 |
|
5243 static void substituteTemplatesInArgList( |
|
5244 const QList<ArgumentList> &srcTempArgLists, |
|
5245 const QList<ArgumentList> &dstTempArgLists, |
|
5246 ArgumentList *src, |
|
5247 ArgumentList *dst, |
|
5248 ArgumentList *funcTempArgs = 0 |
|
5249 ) |
|
5250 { |
|
5251 ArgumentListIterator sali(*src); |
|
5252 Argument *sa=0; |
|
5253 Argument *da=dst->first(); |
|
5254 |
|
5255 for (sali.toFirst();(sa=sali.current());++sali) // for each member argument |
|
5256 { |
|
5257 QCString dstType = substituteTemplatesInString( |
|
5258 srcTempArgLists,dstTempArgLists,funcTempArgs, |
|
5259 sa->type); |
|
5260 QCString dstArray = substituteTemplatesInString( |
|
5261 srcTempArgLists,dstTempArgLists,funcTempArgs, |
|
5262 sa->array); |
|
5263 if (da==0) |
|
5264 { |
|
5265 da=new Argument(*sa); |
|
5266 dst->append(da); |
|
5267 da->type=dstType; |
|
5268 da->array=dstArray; |
|
5269 da=0; |
|
5270 } |
|
5271 else |
|
5272 { |
|
5273 da->type=dstType; |
|
5274 da->type=dstArray; |
|
5275 da=dst->next(); |
|
5276 } |
|
5277 } |
|
5278 dst->constSpecifier = src->constSpecifier; |
|
5279 dst->volatileSpecifier = src->volatileSpecifier; |
|
5280 dst->pureSpecifier = src->pureSpecifier; |
|
5281 //printf("substituteTemplatesInArgList: replacing %s with %s\n", |
|
5282 // argListToString(src).data(),argListToString(dst).data() |
|
5283 // ); |
|
5284 } |
|
5285 |
|
5286 |
|
5287 |
|
5288 /*! This function tries to find a member (in a documented class/file/namespace) |
|
5289 * that corresponds to the function/variable declaration given in \a funcDecl. |
|
5290 * |
|
5291 * The boolean \a overloaded is used to specify whether or not a standard |
|
5292 * overload documentation line should be generated. |
|
5293 * |
|
5294 * The boolean \a isFunc is a hint that indicates that this is a function |
|
5295 * instead of a variable or typedef. |
|
5296 */ |
|
5297 static void findMember(EntryNav *rootNav, |
|
5298 QCString funcDecl, |
|
5299 bool overloaded, |
|
5300 bool isFunc |
|
5301 ) |
|
5302 { |
|
5303 Entry *root = rootNav->entry(); |
|
5304 |
|
5305 Debug::print(Debug::FindMembers,0, |
|
5306 "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d," |
|
5307 "isFunc=%d mGrpId=%d tArgList=%p (#=%d) " |
|
5308 "spec=%d isObjC=%d\n", |
|
5309 root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId, |
|
5310 root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0, |
|
5311 root->spec,root->objc |
|
5312 ); |
|
5313 |
|
5314 QCString scopeName; |
|
5315 QCString className; |
|
5316 QCString namespaceName; |
|
5317 QCString funcType; |
|
5318 QCString funcName; |
|
5319 QCString funcArgs; |
|
5320 QCString funcTempList; |
|
5321 QCString exceptions; |
|
5322 QCString funcSpec; |
|
5323 bool isRelated=FALSE; |
|
5324 bool isMemberOf=FALSE; |
|
5325 bool isFriend=FALSE; |
|
5326 bool done; |
|
5327 do |
|
5328 { |
|
5329 done=TRUE; |
|
5330 if (funcDecl.stripPrefix("friend ")) // treat friends as related members |
|
5331 { |
|
5332 isFriend=TRUE; |
|
5333 done=FALSE; |
|
5334 } |
|
5335 if (funcDecl.stripPrefix("inline ")) |
|
5336 { |
|
5337 root->spec|=Entry::Inline; |
|
5338 done=FALSE; |
|
5339 } |
|
5340 if (funcDecl.stripPrefix("explicit ")) |
|
5341 { |
|
5342 root->spec|=Entry::Explicit; |
|
5343 done=FALSE; |
|
5344 } |
|
5345 if (funcDecl.stripPrefix("mutable ")) |
|
5346 { |
|
5347 root->spec|=Entry::Mutable; |
|
5348 done=FALSE; |
|
5349 } |
|
5350 if (funcDecl.stripPrefix("virtual ")) |
|
5351 { |
|
5352 done=FALSE; |
|
5353 } |
|
5354 } while (!done); |
|
5355 |
|
5356 // delete any ; from the function declaration |
|
5357 int sep; |
|
5358 while ((sep=funcDecl.find(';'))!=-1) |
|
5359 { |
|
5360 funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace(); |
|
5361 } |
|
5362 |
|
5363 // make sure the first character is a space to simplify searching. |
|
5364 if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" "); |
|
5365 |
|
5366 // remove some superfluous spaces |
|
5367 funcDecl= substitute( |
|
5368 substitute( |
|
5369 substitute(funcDecl,"~ ","~"), |
|
5370 ":: ","::" |
|
5371 ), |
|
5372 " ::","::" |
|
5373 ).stripWhiteSpace(); |
|
5374 |
|
5375 //printf("funcDecl=`%s'\n",funcDecl.data()); |
|
5376 if (isFriend && funcDecl.left(6)=="class ") |
|
5377 { |
|
5378 //printf("friend class\n"); |
|
5379 funcDecl=funcDecl.right(funcDecl.length()-6); |
|
5380 funcName = funcDecl.copy(); |
|
5381 } |
|
5382 else if (isFriend && funcDecl.left(7)=="struct ") |
|
5383 { |
|
5384 funcDecl=funcDecl.right(funcDecl.length()-7); |
|
5385 funcName = funcDecl.copy(); |
|
5386 } |
|
5387 else |
|
5388 { |
|
5389 // extract information from the declarations |
|
5390 parseFuncDecl(funcDecl,root->objc,scopeName,funcType,funcName, |
|
5391 funcArgs,funcTempList,exceptions |
|
5392 ); |
|
5393 } |
|
5394 //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n", |
|
5395 // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data()); |
|
5396 |
|
5397 // the class name can also be a namespace name, we decide this later. |
|
5398 // if a related class name is specified and the class name could |
|
5399 // not be derived from the function declaration, then use the |
|
5400 // related field. |
|
5401 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n", |
|
5402 // scopeName.data(),className.data(),namespaceName.data()); |
|
5403 if (!root->relates.isEmpty()) |
|
5404 { // related member, prefix user specified scope |
|
5405 isRelated=TRUE; |
|
5406 isMemberOf=(root->relatesType == MemberOf); |
|
5407 if (getClass(root->relates)==0 && !scopeName.isEmpty()) |
|
5408 { |
|
5409 scopeName= mergeScopes(scopeName,root->relates); |
|
5410 } |
|
5411 else |
|
5412 { |
|
5413 scopeName = root->relates; |
|
5414 } |
|
5415 } |
|
5416 |
|
5417 if (root->relates.isEmpty() && rootNav->parent() && |
|
5418 ((rootNav->parent()->section()&Entry::SCOPE_MASK) || |
|
5419 (rootNav->parent()->section()==Entry::OBJCIMPL_SEC) |
|
5420 ) && |
|
5421 !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName |
|
5422 // with the scope in which it was found |
|
5423 { |
|
5424 QCString joinedName = rootNav->parent()->name()+"::"+scopeName; |
|
5425 if (!scopeName.isEmpty() && |
|
5426 (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName))) |
|
5427 { |
|
5428 scopeName = joinedName; |
|
5429 } |
|
5430 else |
|
5431 { |
|
5432 scopeName = mergeScopes(rootNav->parent()->name(),scopeName); |
|
5433 } |
|
5434 } |
|
5435 else // see if we can prefix a namespace or class that is used from the file |
|
5436 { |
|
5437 FileDef *fd=rootNav->fileDef(); |
|
5438 if (fd) |
|
5439 { |
|
5440 NamespaceSDict *fnl = fd->getUsedNamespaces(); |
|
5441 if (fnl) |
|
5442 { |
|
5443 QCString joinedName; |
|
5444 NamespaceDef *fnd; |
|
5445 NamespaceSDict::Iterator nsdi(*fnl); |
|
5446 for (nsdi.toFirst();(fnd=nsdi.current());++nsdi) |
|
5447 { |
|
5448 joinedName = fnd->name()+"::"+scopeName; |
|
5449 if (Doxygen::namespaceSDict->find(joinedName)) |
|
5450 { |
|
5451 scopeName=joinedName; |
|
5452 break; |
|
5453 } |
|
5454 } |
|
5455 } |
|
5456 } |
|
5457 } |
|
5458 scopeName=stripTemplateSpecifiersFromScope( |
|
5459 removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); |
|
5460 |
|
5461 // funcSpec contains the last template specifiers of the given scope. |
|
5462 // If this method does not have any template arguments or they are |
|
5463 // empty while funcSpec is not empty we assume this is a |
|
5464 // specialization of a method. If not, we clear the funcSpec and treat |
|
5465 // this as a normal method of a template class. |
|
5466 if (!(root->tArgLists && |
|
5467 root->tArgLists->count()>0 && |
|
5468 root->tArgLists->first()->count()==0 |
|
5469 ) |
|
5470 ) |
|
5471 { |
|
5472 funcSpec.resize(0); |
|
5473 } |
|
5474 |
|
5475 // split scope into a namespace and a class part |
|
5476 extractNamespaceName(scopeName,className,namespaceName,TRUE); |
|
5477 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n", |
|
5478 // scopeName.data(),className.data(),namespaceName.data()); |
|
5479 |
|
5480 //namespaceName=removeAnonymousScopes(namespaceName); |
|
5481 if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace... |
|
5482 |
|
5483 //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data()); |
|
5484 // merge class and namespace scopes again |
|
5485 scopeName.resize(0); |
|
5486 if (!namespaceName.isEmpty()) |
|
5487 { |
|
5488 if (className.isEmpty()) |
|
5489 { |
|
5490 scopeName=namespaceName; |
|
5491 } |
|
5492 else if (!root->relates.isEmpty() || // relates command with explicit scope |
|
5493 !getClass(className)) // class name only exists in a namespace |
|
5494 { |
|
5495 scopeName=namespaceName+"::"+className; |
|
5496 } |
|
5497 else |
|
5498 { |
|
5499 scopeName=className; |
|
5500 } |
|
5501 } |
|
5502 else if (!className.isEmpty()) |
|
5503 { |
|
5504 scopeName=className; |
|
5505 } |
|
5506 //printf("new scope=`%s'\n",scopeName.data()); |
|
5507 |
|
5508 QCString tempScopeName=scopeName; |
|
5509 ClassDef *cd=getClass(scopeName); |
|
5510 if (cd) |
|
5511 { |
|
5512 if (root->tArgLists) root->tArgLists->first(); |
|
5513 if (funcSpec.isEmpty()) |
|
5514 { |
|
5515 tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists); |
|
5516 } |
|
5517 else |
|
5518 { |
|
5519 tempScopeName=scopeName+funcSpec; |
|
5520 } |
|
5521 } |
|
5522 //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n", |
|
5523 // scopeName.data(),cd,root->tArgLists,tempScopeName.data()); |
|
5524 |
|
5525 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); |
|
5526 // rebuild the function declaration (needed to get the scope right). |
|
5527 if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES")) |
|
5528 { |
|
5529 if (!funcType.isEmpty()) |
|
5530 { |
|
5531 if (isFunc) // a function -> we use argList for the arguments |
|
5532 { |
|
5533 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList; |
|
5534 } |
|
5535 else |
|
5536 { |
|
5537 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs; |
|
5538 } |
|
5539 } |
|
5540 else |
|
5541 { |
|
5542 if (isFunc) // a function => we use argList for the arguments |
|
5543 { |
|
5544 funcDecl=tempScopeName+"::"+funcName+funcTempList; |
|
5545 } |
|
5546 else // variable => add `argument' list |
|
5547 { |
|
5548 funcDecl=tempScopeName+"::"+funcName+funcArgs; |
|
5549 } |
|
5550 } |
|
5551 } |
|
5552 else // build declaration without scope |
|
5553 { |
|
5554 if (!funcType.isEmpty()) // but with a type |
|
5555 { |
|
5556 if (isFunc) // function => omit argument list |
|
5557 { |
|
5558 funcDecl=funcType+" "+funcName+funcTempList; |
|
5559 } |
|
5560 else // variable => add `argument' list |
|
5561 { |
|
5562 funcDecl=funcType+" "+funcName+funcArgs; |
|
5563 } |
|
5564 } |
|
5565 else // no type |
|
5566 { |
|
5567 if (isFunc) |
|
5568 { |
|
5569 funcDecl=funcName+funcTempList; |
|
5570 } |
|
5571 else |
|
5572 { |
|
5573 funcDecl=funcName+funcArgs; |
|
5574 } |
|
5575 } |
|
5576 } |
|
5577 |
|
5578 if (funcType=="template class" && !funcTempList.isEmpty()) |
|
5579 return; // ignore explicit template instantiations |
|
5580 |
|
5581 Debug::print(Debug::FindMembers,0, |
|
5582 "findMember() Parse results:\n" |
|
5583 " namespaceName=`%s'\n" |
|
5584 " className=`%s`\n" |
|
5585 " funcType=`%s'\n" |
|
5586 " funcSpec=`%s'\n" |
|
5587 " funcName=`%s'\n" |
|
5588 " funcArgs=`%s'\n" |
|
5589 " funcTempList=`%s'\n" |
|
5590 " funcDecl=`%s'\n" |
|
5591 " related=`%s'\n" |
|
5592 " exceptions=`%s'\n" |
|
5593 " isRelated=%d\n" |
|
5594 " isMemberOf=%d\n" |
|
5595 " isFriend=%d\n" |
|
5596 " isFunc=%d\n\n", |
|
5597 namespaceName.data(),className.data(), |
|
5598 funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(), |
|
5599 funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend, |
|
5600 isFunc |
|
5601 ); |
|
5602 |
|
5603 MemberName *mn=0; |
|
5604 if (!funcName.isEmpty()) // function name is valid |
|
5605 { |
|
5606 Debug::print(Debug::FindMembers,0, |
|
5607 "1. funcName=`%s'\n",funcName.data()); |
|
5608 if (funcName.left(9)=="operator ") // strip class scope from cast operator |
|
5609 { |
|
5610 funcName = substitute(funcName,className+"::",""); |
|
5611 } |
|
5612 if (!funcTempList.isEmpty()) // try with member specialization |
|
5613 { |
|
5614 mn=Doxygen::memberNameSDict->find(funcName+funcTempList); |
|
5615 } |
|
5616 if (mn==0) // try without specialization |
|
5617 { |
|
5618 mn=Doxygen::memberNameSDict->find(funcName); |
|
5619 } |
|
5620 if (!isRelated && mn) // function name already found |
|
5621 { |
|
5622 Debug::print(Debug::FindMembers,0, |
|
5623 "2. member name exists (%d members with this name)\n",mn->count()); |
|
5624 if (!className.isEmpty()) // class name is valid |
|
5625 { |
|
5626 if (funcSpec.isEmpty()) // not a member specialization |
|
5627 { |
|
5628 int count=0; |
|
5629 int noMatchCount=0; |
|
5630 MemberNameIterator mni(*mn); |
|
5631 MemberDef *md; |
|
5632 bool memFound=FALSE; |
|
5633 for (mni.toFirst();!memFound && (md=mni.current());++mni) |
|
5634 { |
|
5635 ClassDef *cd=md->getClassDef(); |
|
5636 Debug::print(Debug::FindMembers,0, |
|
5637 "3. member definition found, " |
|
5638 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n", |
|
5639 scopeName.data(),cd ? cd->name().data() : "<none>", |
|
5640 md->argsString(), |
|
5641 root->fileName.data()); |
|
5642 //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data()); |
|
5643 FileDef *fd=rootNav->fileDef(); |
|
5644 NamespaceDef *nd=0; |
|
5645 if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName); |
|
5646 |
|
5647 //printf("scopeName %s->%s\n",scopeName.data(), |
|
5648 // stripTemplateSpecifiersFromScope(scopeName,FALSE).data()); |
|
5649 |
|
5650 ClassDef *tcd=findClassDefinition(fd,nd,scopeName); |
|
5651 if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName) |
|
5652 { |
|
5653 // don't be fooled by anonymous scopes |
|
5654 tcd=cd; |
|
5655 } |
|
5656 //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n", |
|
5657 // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd); |
|
5658 |
|
5659 if (cd && tcd==cd) // member's classes match |
|
5660 { |
|
5661 Debug::print(Debug::FindMembers,0, |
|
5662 "4. class definition %s found\n",cd->name().data()); |
|
5663 |
|
5664 // get the template parameter lists found at the member declaration |
|
5665 QList<ArgumentList> declTemplArgs; |
|
5666 cd->getTemplateParameterLists(declTemplArgs); |
|
5667 LockingPtr<ArgumentList> templAl = md->templateArguments(); |
|
5668 if (templAl!=0) |
|
5669 { |
|
5670 declTemplArgs.append(templAl.pointer()); |
|
5671 } |
|
5672 |
|
5673 // get the template parameter lists found at the member definition |
|
5674 QList<ArgumentList> *defTemplArgs = root->tArgLists; |
|
5675 //printf("defTemplArgs=%p\n",defTemplArgs); |
|
5676 |
|
5677 // do we replace the decl argument lists with the def argument lists? |
|
5678 bool substDone=FALSE; |
|
5679 ArgumentList *argList=0; |
|
5680 |
|
5681 /* substitute the occurrences of class template names in the |
|
5682 * argument list before matching |
|
5683 */ |
|
5684 LockingPtr<ArgumentList> mdAl = md->argumentList(); |
|
5685 if (declTemplArgs.count()>0 && defTemplArgs && |
|
5686 declTemplArgs.count()==defTemplArgs->count() && |
|
5687 mdAl.pointer() |
|
5688 ) |
|
5689 { |
|
5690 /* the function definition has template arguments |
|
5691 * and the class definition also has template arguments, so |
|
5692 * we must substitute the template names of the class by that |
|
5693 * of the function definition before matching. |
|
5694 */ |
|
5695 argList = new ArgumentList; |
|
5696 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs, |
|
5697 mdAl.pointer(),argList); |
|
5698 |
|
5699 substDone=TRUE; |
|
5700 } |
|
5701 else /* no template arguments, compare argument lists directly */ |
|
5702 { |
|
5703 argList = mdAl.pointer(); |
|
5704 } |
|
5705 |
|
5706 Debug::print(Debug::FindMembers,0, |
|
5707 "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n", |
|
5708 argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(), |
|
5709 className.data(),namespaceName.data() |
|
5710 ); |
|
5711 |
|
5712 bool matching= |
|
5713 md->isVariable() || md->isTypedef() || // needed for function pointers |
|
5714 (mdAl.pointer()==0 && root->argList->count()==0) || |
|
5715 matchArguments2( |
|
5716 md->getClassDef(),md->getFileDef(),argList, |
|
5717 cd,fd,root->argList, |
|
5718 TRUE); |
|
5719 |
|
5720 Debug::print(Debug::FindMembers,0, |
|
5721 "6. match results of matchArguments2 = %d\n",matching); |
|
5722 |
|
5723 if (substDone) // found a new argument list |
|
5724 { |
|
5725 if (matching) // replace member's argument list |
|
5726 { |
|
5727 md->setDefinitionTemplateParameterLists(root->tArgLists); |
|
5728 md->setArgumentList(argList); // new owner of the list => no delete |
|
5729 } |
|
5730 else // no match |
|
5731 { |
|
5732 if (!funcTempList.isEmpty() && |
|
5733 isSpecialization(declTemplArgs,*defTemplArgs)) |
|
5734 { |
|
5735 // check if we are dealing with a partial template |
|
5736 // specialization. In this case we add it to the class |
|
5737 // even though the member arguments do not match. |
|
5738 |
|
5739 // TODO: copy other aspects? |
|
5740 root->protection=md->protection(); // copy protection level |
|
5741 addMethodToClass(rootNav,cd,md->name(),isFriend); |
|
5742 return; |
|
5743 } |
|
5744 delete argList; |
|
5745 } |
|
5746 } |
|
5747 if (matching) |
|
5748 { |
|
5749 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */); |
|
5750 count++; |
|
5751 memFound=TRUE; |
|
5752 } |
|
5753 } |
|
5754 else if (cd && cd!=tcd) // we did find a class with the same name as cd |
|
5755 // but in a different namespace |
|
5756 { |
|
5757 noMatchCount++; |
|
5758 } |
|
5759 } |
|
5760 if (count==0 && rootNav->parent() && |
|
5761 rootNav->parent()->section()==Entry::OBJCIMPL_SEC) |
|
5762 { |
|
5763 goto localObjCMethod; |
|
5764 } |
|
5765 if (count==0 && !(isFriend && funcType=="class")) |
|
5766 { |
|
5767 int candidates=0; |
|
5768 if (mn->count()>0) |
|
5769 { |
|
5770 //printf("Assume template class\n"); |
|
5771 for (mni.toFirst();(md=mni.current());++mni) |
|
5772 { |
|
5773 ClassDef *cd=md->getClassDef(); |
|
5774 //printf("cd->name()==%s className=%s\n",cd->name().data(),className.data()); |
|
5775 if (cd!=0 && rightScopeMatch(cd->name(),className)) |
|
5776 { |
|
5777 LockingPtr<ArgumentList> templAl = md->templateArguments(); |
|
5778 if (root->tArgLists && templAl!=0 && |
|
5779 root->tArgLists->getLast()->count()<=templAl->count()) |
|
5780 { |
|
5781 addMethodToClass(rootNav,cd,md->name(),isFriend); |
|
5782 return; |
|
5783 } |
|
5784 candidates++; |
|
5785 } |
|
5786 } |
|
5787 } |
|
5788 |
|
5789 warn(root->fileName,root->startLine, |
|
5790 "Warning: no %smatching class member found for", |
|
5791 noMatchCount>1 ? "uniquely " : "" |
|
5792 ); |
|
5793 |
|
5794 if (root->tArgLists) |
|
5795 { |
|
5796 QListIterator<ArgumentList> alli(*root->tArgLists); |
|
5797 ArgumentList *al; |
|
5798 for (;(al=alli.current());++alli) |
|
5799 { |
|
5800 warn_cont(" template %s\n",tempArgListToString(al).data()); |
|
5801 } |
|
5802 } |
|
5803 QCString fullFuncDecl=funcDecl.copy(); |
|
5804 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); |
|
5805 |
|
5806 warn_cont(" %s\n",fullFuncDecl.data()); |
|
5807 |
|
5808 if (candidates>0) |
|
5809 { |
|
5810 warn_cont("Possible candidates:\n"); |
|
5811 for (mni.toFirst();(md=mni.current());++mni) |
|
5812 { |
|
5813 ClassDef *cd=md->getClassDef(); |
|
5814 if (cd!=0 && rightScopeMatch(cd->name(),className)) |
|
5815 { |
|
5816 LockingPtr<ArgumentList> templAl = md->templateArguments(); |
|
5817 if (templAl!=0) |
|
5818 { |
|
5819 warn_cont(" template %s\n",tempArgListToString(templAl.pointer()).data()); |
|
5820 } |
|
5821 warn_cont(" "); |
|
5822 if (md->typeString()) |
|
5823 { |
|
5824 warn_cont("%s ",md->typeString()); |
|
5825 } |
|
5826 QCString qScope = cd->qualifiedNameWithTemplateParameters(); |
|
5827 if (!qScope.isEmpty()) warn_cont("%s::%s",qScope.data(),md->name().data()); |
|
5828 if (md->argsString()) warn_cont("%s",md->argsString()); |
|
5829 if (noMatchCount>1) warn_cont(" at line %d of file %s",md->getDefLine(),md->getDefFileName().data()); |
|
5830 warn_cont("\n"); |
|
5831 } |
|
5832 } |
|
5833 } |
|
5834 } |
|
5835 } |
|
5836 else if (cd) // member specialization |
|
5837 { |
|
5838 MemberDef::MemberType mtype=MemberDef::Function; |
|
5839 ArgumentList *tArgList = new ArgumentList; |
|
5840 // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists); |
|
5841 MemberDef *md=new MemberDef( |
|
5842 root->fileName,root->startLine, |
|
5843 funcType,funcName,funcArgs,exceptions, |
|
5844 root->protection,root->virt,root->stat,Member, |
|
5845 mtype,tArgList,root->argList); |
|
5846 //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data()); |
|
5847 md->setTagInfo(rootNav->tagInfo()); |
|
5848 md->setMemberClass(cd); |
|
5849 md->setTemplateSpecialization(TRUE); |
|
5850 md->setTypeConstraints(root->typeConstr); |
|
5851 md->setDefinition(funcDecl); |
|
5852 md->enableCallGraph(root->callGraph); |
|
5853 md->enableCallerGraph(root->callerGraph); |
|
5854 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
5855 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
5856 md->setDocsForDefinition(!root->proto); |
|
5857 md->setPrototype(root->proto); |
|
5858 md->addSectionsToDefinition(root->anchors); |
|
5859 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
5860 FileDef *fd=rootNav->fileDef(); |
|
5861 md->setBodyDef(fd); |
|
5862 md->setMemberSpecifiers(root->spec); |
|
5863 md->setMemberGroupId(root->mGrpId); |
|
5864 mn->append(md); |
|
5865 cd->insertMember(md); |
|
5866 md->setRefItems(root->sli); |
|
5867 delete tArgList; |
|
5868 } |
|
5869 else |
|
5870 { |
|
5871 //printf("*** Specialized member %s of unknown scope %s%s found!\n", |
|
5872 // scopeName.data(),funcName.data(),funcArgs.data()); |
|
5873 } |
|
5874 } |
|
5875 else if (overloaded) // check if the function belongs to only one class |
|
5876 { |
|
5877 // for unique overloaded member we allow the class to be |
|
5878 // omitted, this is to be Qt compatable. Using this should |
|
5879 // however be avoided, because it is error prone |
|
5880 MemberNameIterator mni(*mn); |
|
5881 MemberDef *md=mni.toFirst(); |
|
5882 ASSERT(md); |
|
5883 ClassDef *cd=md->getClassDef(); |
|
5884 ASSERT(cd); |
|
5885 QCString className=cd->name().copy(); |
|
5886 ++mni; |
|
5887 bool unique=TRUE; |
|
5888 for (;(md=mni.current());++mni) |
|
5889 { |
|
5890 ClassDef *cd=md->getClassDef(); |
|
5891 if (className!=cd->name()) unique=FALSE; |
|
5892 } |
|
5893 if (unique) |
|
5894 { |
|
5895 MemberDef::MemberType mtype; |
|
5896 if (root->mtype==Signal) mtype=MemberDef::Signal; |
|
5897 else if (root->mtype==Slot) mtype=MemberDef::Slot; |
|
5898 else if (root->mtype==DCOP) mtype=MemberDef::DCOP; |
|
5899 else mtype=MemberDef::Function; |
|
5900 |
|
5901 // new overloaded member function |
|
5902 ArgumentList *tArgList = |
|
5903 getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists); |
|
5904 //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data()); |
|
5905 MemberDef *md=new MemberDef( |
|
5906 root->fileName,root->startLine, |
|
5907 funcType,funcName,funcArgs,exceptions, |
|
5908 root->protection,root->virt,root->stat,Related, |
|
5909 mtype,tArgList,root->argList); |
|
5910 md->setTagInfo(rootNav->tagInfo()); |
|
5911 md->setTypeConstraints(root->typeConstr); |
|
5912 md->setMemberClass(cd); |
|
5913 md->setDefinition(funcDecl); |
|
5914 md->enableCallGraph(root->callGraph); |
|
5915 md->enableCallerGraph(root->callerGraph); |
|
5916 QCString doc=getOverloadDocs(); |
|
5917 doc+="<p>"; |
|
5918 doc+=root->doc; |
|
5919 md->setDocumentation(doc,root->docFile,root->docLine); |
|
5920 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
5921 md->setDocsForDefinition(!root->proto); |
|
5922 md->setPrototype(root->proto); |
|
5923 md->addSectionsToDefinition(root->anchors); |
|
5924 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
5925 FileDef *fd=rootNav->fileDef(); |
|
5926 md->setBodyDef(fd); |
|
5927 md->setMemberSpecifiers(root->spec); |
|
5928 md->setMemberGroupId(root->mGrpId); |
|
5929 mn->append(md); |
|
5930 cd->insertMember(md); |
|
5931 cd->insertUsedFile(root->fileName); |
|
5932 md->setRefItems(root->sli); |
|
5933 } |
|
5934 } |
|
5935 else // unrelated function with the same name as a member |
|
5936 { |
|
5937 if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl)) |
|
5938 { |
|
5939 QCString fullFuncDecl=funcDecl.copy(); |
|
5940 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); |
|
5941 warn(root->fileName,root->startLine, |
|
5942 "Warning: Cannot determine class for function\n%s", |
|
5943 fullFuncDecl.data() |
|
5944 ); |
|
5945 } |
|
5946 } |
|
5947 } |
|
5948 else if (isRelated && !root->relates.isEmpty()) |
|
5949 { |
|
5950 Debug::print(Debug::FindMembers,0,"2. related function\n" |
|
5951 " scopeName=%s className=%s\n",scopeName.data(),className.data()); |
|
5952 if (className.isEmpty()) className=root->relates; |
|
5953 ClassDef *cd; |
|
5954 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); |
|
5955 if ((cd=getClass(scopeName))) |
|
5956 { |
|
5957 bool newMember=TRUE; // assume we have a new member |
|
5958 bool newMemberName=FALSE; |
|
5959 bool isDefine=FALSE; |
|
5960 { |
|
5961 MemberName *mn = Doxygen::functionNameSDict->find(funcName); |
|
5962 if (mn) |
|
5963 { |
|
5964 MemberDef *md = mn->first(); |
|
5965 while (md && !isDefine) |
|
5966 { |
|
5967 isDefine = isDefine || md->isDefine(); |
|
5968 md = mn->next(); |
|
5969 } |
|
5970 } |
|
5971 } |
|
5972 |
|
5973 FileDef *fd=rootNav->fileDef(); |
|
5974 |
|
5975 if ((mn=Doxygen::memberNameSDict->find(funcName))==0) |
|
5976 { |
|
5977 mn=new MemberName(funcName); |
|
5978 newMemberName=TRUE; // we create a new member name |
|
5979 } |
|
5980 else |
|
5981 { |
|
5982 MemberDef *rmd=mn->first(); |
|
5983 while (rmd && newMember) // see if we got another member with matching arguments |
|
5984 { |
|
5985 LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); |
|
5986 |
|
5987 newMember=newMember && |
|
5988 !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), |
|
5989 cd,fd,root->argList, |
|
5990 TRUE); |
|
5991 if (newMember) rmd=mn->next(); |
|
5992 } |
|
5993 if (!newMember && rmd) // member already exists as rmd -> add docs |
|
5994 { |
|
5995 //printf("addMemberDocs for related member %s\n",root->name.data()); |
|
5996 //rmd->setMemberDefTemplateArguments(root->mtArgList); |
|
5997 addMemberDocs(rootNav,rmd,funcDecl,0,overloaded); |
|
5998 } |
|
5999 } |
|
6000 |
|
6001 if (newMember) // need to create a new member |
|
6002 { |
|
6003 MemberDef::MemberType mtype; |
|
6004 if (isDefine) |
|
6005 mtype=MemberDef::Define; |
|
6006 else if (root->mtype==Signal) |
|
6007 mtype=MemberDef::Signal; |
|
6008 else if (root->mtype==Slot) |
|
6009 mtype=MemberDef::Slot; |
|
6010 else if (root->mtype==DCOP) |
|
6011 mtype=MemberDef::DCOP; |
|
6012 else |
|
6013 mtype=MemberDef::Function; |
|
6014 |
|
6015 //printf("New related name `%s' `%d'\n",funcName.data(), |
|
6016 // root->argList ? (int)root->argList->count() : -1); |
|
6017 |
|
6018 // new related (member) function |
|
6019 #if 0 // removed as it doesn't handle related template functions correctly |
|
6020 ArgumentList *tArgList = |
|
6021 getTemplateArgumentsFromName(scopeName+"::"+funcName,root->tArgLists); |
|
6022 MemberDef *md=new MemberDef( |
|
6023 root->fileName,root->startLine, |
|
6024 funcType,funcName,funcArgs,exceptions, |
|
6025 root->protection,root->virt,root->stat,TRUE, |
|
6026 mtype,tArgList,funcArgs.isEmpty() ? 0 : root->argList); |
|
6027 #endif |
|
6028 // first note that we pass: |
|
6029 // (root->tArgLists ? root->tArgLists->last() : 0) |
|
6030 // for the template arguments fo the new "member." |
|
6031 // this accurately reflects the template arguments of |
|
6032 // the related function, which don't have to do with |
|
6033 // those of the related class. |
|
6034 MemberDef *md=new MemberDef( |
|
6035 root->fileName,root->startLine, |
|
6036 funcType,funcName,funcArgs,exceptions, |
|
6037 root->protection,root->virt, |
|
6038 root->stat && !isMemberOf, |
|
6039 isMemberOf ? Foreign : isRelated ? Related : Member, |
|
6040 mtype, |
|
6041 (root->tArgLists ? root->tArgLists->last() : 0), |
|
6042 funcArgs.isEmpty() ? 0 : root->argList); |
|
6043 // |
|
6044 // we still have the problem that |
|
6045 // MemberDef::writeDocumentation() in memberdef.cpp |
|
6046 // writes the template argument list for the class, |
|
6047 // as if this member is a member of the class. |
|
6048 // fortunately, MemberDef::writeDocumentation() has |
|
6049 // a special mechanism that allows us to totally |
|
6050 // override the set of template argument lists that |
|
6051 // are printed. We use that and set it to the |
|
6052 // template argument lists of the related function. |
|
6053 // |
|
6054 md->setDefinitionTemplateParameterLists(root->tArgLists); |
|
6055 |
|
6056 md->setTagInfo(rootNav->tagInfo()); |
|
6057 |
|
6058 |
|
6059 |
|
6060 //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n", |
|
6061 // funcName.data(),funcDecl.data(),root->bodyLine); |
|
6062 |
|
6063 // try to find the matching line number of the body from the |
|
6064 // global function list |
|
6065 bool found=FALSE; |
|
6066 if (root->bodyLine==-1) |
|
6067 { |
|
6068 MemberName *rmn=Doxygen::functionNameSDict->find(funcName); |
|
6069 if (rmn) |
|
6070 { |
|
6071 MemberDef *rmd=rmn->first(); |
|
6072 while (rmd && !found) // see if we got another member with matching arguments |
|
6073 { |
|
6074 LockingPtr<ArgumentList> rmdAl = rmd->argumentList(); |
|
6075 // check for matching argument lists |
|
6076 if ( |
|
6077 matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(), |
|
6078 cd,fd,root->argList, |
|
6079 TRUE) |
|
6080 ) |
|
6081 { |
|
6082 found=TRUE; |
|
6083 } |
|
6084 if (!found) rmd=rmn->next(); |
|
6085 } |
|
6086 if (rmd) // member found -> copy line number info |
|
6087 { |
|
6088 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine()); |
|
6089 md->setBodyDef(rmd->getBodyDef()); |
|
6090 //md->setBodyMember(rmd); |
|
6091 } |
|
6092 } |
|
6093 } |
|
6094 if (!found) // line number could not be found or is available in this |
|
6095 // entry |
|
6096 { |
|
6097 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
6098 md->setBodyDef(fd); |
|
6099 } |
|
6100 |
|
6101 //if (root->mGrpId!=-1) |
|
6102 //{ |
|
6103 // md->setMemberGroup(memberGroupDict[root->mGrpId]); |
|
6104 //} |
|
6105 md->setMemberClass(cd); |
|
6106 md->setMemberSpecifiers(root->spec); |
|
6107 md->setDefinition(funcDecl); |
|
6108 md->enableCallGraph(root->callGraph); |
|
6109 md->enableCallerGraph(root->callerGraph); |
|
6110 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
6111 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
6112 md->setDocsForDefinition(!root->proto); |
|
6113 md->setPrototype(root->proto); |
|
6114 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
6115 md->addSectionsToDefinition(root->anchors); |
|
6116 md->setMemberGroupId(root->mGrpId); |
|
6117 //md->setMemberDefTemplateArguments(root->mtArgList); |
|
6118 mn->append(md); |
|
6119 cd->insertMember(md); |
|
6120 cd->insertUsedFile(root->fileName); |
|
6121 md->setRefItems(root->sli); |
|
6122 if (root->relatesType == Duplicate) md->setRelatedAlso(cd); |
|
6123 addMemberToGroups(root,md); |
|
6124 //printf("Adding member=%s\n",md->name().data()); |
|
6125 if (newMemberName) |
|
6126 { |
|
6127 //Doxygen::memberNameList.append(mn); |
|
6128 //Doxygen::memberNameDict.insert(funcName,mn); |
|
6129 Doxygen::memberNameSDict->append(funcName,mn); |
|
6130 } |
|
6131 } |
|
6132 if (root->relatesType == Duplicate) |
|
6133 { |
|
6134 if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl)) |
|
6135 { |
|
6136 QCString fullFuncDecl=funcDecl.copy(); |
|
6137 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE); |
|
6138 warn(root->fileName,root->startLine, |
|
6139 "Warning: Cannot determine file/namespace for relatedalso function\n%s", |
|
6140 fullFuncDecl.data() |
|
6141 ); |
|
6142 } |
|
6143 } |
|
6144 } |
|
6145 else |
|
6146 { |
|
6147 warn_undoc(root->fileName,root->startLine, |
|
6148 "Warning: class `%s' for related function `%s' is not " |
|
6149 "documented.", |
|
6150 className.data(),funcName.data() |
|
6151 ); |
|
6152 } |
|
6153 } |
|
6154 else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC) |
|
6155 { |
|
6156 localObjCMethod: |
|
6157 ClassDef *cd; |
|
6158 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data()); |
|
6159 if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName))) |
|
6160 { |
|
6161 //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data()); |
|
6162 MemberDef *md=new MemberDef( |
|
6163 root->fileName,root->startLine, |
|
6164 funcType,funcName,funcArgs,exceptions, |
|
6165 root->protection,root->virt,root->stat,Member, |
|
6166 MemberDef::Function,0,root->argList); |
|
6167 md->setTagInfo(rootNav->tagInfo()); |
|
6168 md->makeImplementationDetail(); |
|
6169 md->setMemberClass(cd); |
|
6170 md->setDefinition(funcDecl); |
|
6171 md->enableCallGraph(root->callGraph); |
|
6172 md->enableCallerGraph(root->callerGraph); |
|
6173 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
6174 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
6175 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
6176 md->setDocsForDefinition(!root->proto); |
|
6177 md->setPrototype(root->proto); |
|
6178 md->addSectionsToDefinition(root->anchors); |
|
6179 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
6180 FileDef *fd=rootNav->fileDef(); |
|
6181 md->setBodyDef(fd); |
|
6182 md->setMemberSpecifiers(root->spec); |
|
6183 md->setMemberGroupId(root->mGrpId); |
|
6184 cd->insertMember(md); |
|
6185 cd->insertUsedFile(root->fileName); |
|
6186 md->setRefItems(root->sli); |
|
6187 if ((mn=Doxygen::memberNameSDict->find(root->name))) |
|
6188 { |
|
6189 mn->append(md); |
|
6190 } |
|
6191 else |
|
6192 { |
|
6193 mn = new MemberName(root->name); |
|
6194 mn->append(md); |
|
6195 Doxygen::memberNameSDict->append(root->name,mn); |
|
6196 } |
|
6197 } |
|
6198 else |
|
6199 { |
|
6200 // local objective C method found for class without interface |
|
6201 } |
|
6202 } |
|
6203 else // unrelated not overloaded member found |
|
6204 { |
|
6205 bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl); |
|
6206 if (className.isEmpty() && !globMem) |
|
6207 { |
|
6208 warn(root->fileName,root->startLine, |
|
6209 "Warning: class for member `%s' cannot " |
|
6210 "be found.", funcName.data() |
|
6211 ); |
|
6212 } |
|
6213 else if (!className.isEmpty() && !globMem) |
|
6214 { |
|
6215 warn(root->fileName,root->startLine, |
|
6216 "Warning: member `%s' of class `%s' cannot be found", |
|
6217 funcName.data(),className.data()); |
|
6218 } |
|
6219 } |
|
6220 } |
|
6221 else |
|
6222 { |
|
6223 // this should not be called |
|
6224 warn(root->fileName,root->startLine, |
|
6225 "Warning: member with no name found."); |
|
6226 } |
|
6227 return; |
|
6228 } |
|
6229 |
|
6230 //---------------------------------------------------------------------- |
|
6231 // find the members corresponding to the different documentation blocks |
|
6232 // that are extracted from the sources. |
|
6233 |
|
6234 static void filterMemberDocumentation(EntryNav *rootNav) |
|
6235 { |
|
6236 Entry *root = rootNav->entry(); |
|
6237 int i=-1,l; |
|
6238 Debug::print(Debug::FindMembers,0, |
|
6239 "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n", |
|
6240 root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId |
|
6241 ); |
|
6242 //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data()); |
|
6243 bool isFunc=TRUE; |
|
6244 |
|
6245 if (root->relatesType == Duplicate && !root->relates.isEmpty()) |
|
6246 { |
|
6247 QCString tmp = root->relates; |
|
6248 root->relates.resize(0); |
|
6249 filterMemberDocumentation(rootNav); |
|
6250 root->relates = tmp; |
|
6251 } |
|
6252 |
|
6253 if ( // detect func variable/typedef to func ptr |
|
6254 (i=findFunctionPtr(root->type,&l))!=-1 |
|
6255 ) |
|
6256 { |
|
6257 //printf("Fixing function pointer!\n"); |
|
6258 // fix type and argument |
|
6259 root->args.prepend(root->type.right(root->type.length()-i-l)); |
|
6260 root->type=root->type.left(i+l); |
|
6261 //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data()); |
|
6262 isFunc=FALSE; |
|
6263 } |
|
6264 else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) |
|
6265 // detect function types marked as functions |
|
6266 { |
|
6267 isFunc=FALSE; |
|
6268 } |
|
6269 |
|
6270 //printf("Member %s isFunc=%d\n",root->name.data(),isFunc); |
|
6271 if (root->section==Entry::MEMBERDOC_SEC) |
|
6272 { |
|
6273 //printf("Documentation for inline member `%s' found args=`%s'\n", |
|
6274 // root->name.data(),root->args.data()); |
|
6275 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data()); |
|
6276 if (root->type.isEmpty()) |
|
6277 { |
|
6278 findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc); |
|
6279 } |
|
6280 else |
|
6281 { |
|
6282 findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc); |
|
6283 } |
|
6284 } |
|
6285 else if (root->section==Entry::OVERLOADDOC_SEC) |
|
6286 { |
|
6287 //printf("Overloaded member %s found\n",root->name.data()); |
|
6288 findMember(rootNav,root->name,TRUE,isFunc); |
|
6289 } |
|
6290 else if |
|
6291 ((root->section==Entry::FUNCTION_SEC // function |
|
6292 || |
|
6293 (root->section==Entry::VARIABLE_SEC && // variable |
|
6294 !root->type.isEmpty() && // with a type |
|
6295 g_compoundKeywordDict.find(root->type)==0 // that is not a keyword |
|
6296 // (to skip forward declaration of class etc.) |
|
6297 ) |
|
6298 ) |
|
6299 ) |
|
6300 { |
|
6301 //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n", |
|
6302 // root->name.data(),root->args.data(),root->exception.data()); |
|
6303 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data()); |
|
6304 //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data()); |
|
6305 if (root->type=="friend class" || root->type=="friend struct" || |
|
6306 root->type=="friend union") |
|
6307 { |
|
6308 findMember(rootNav, |
|
6309 root->type+" "+ |
|
6310 root->name, |
|
6311 FALSE,FALSE); |
|
6312 |
|
6313 } |
|
6314 else if (!root->type.isEmpty()) |
|
6315 { |
|
6316 findMember(rootNav, |
|
6317 root->type+" "+ |
|
6318 root->inside+ |
|
6319 root->name+ |
|
6320 root->args+ |
|
6321 root->exception, |
|
6322 FALSE,isFunc); |
|
6323 } |
|
6324 else |
|
6325 { |
|
6326 findMember(rootNav, |
|
6327 root->inside+ |
|
6328 root->name+ |
|
6329 root->args+ |
|
6330 root->exception, |
|
6331 FALSE,isFunc); |
|
6332 } |
|
6333 } |
|
6334 else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty()) |
|
6335 { |
|
6336 findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty()); |
|
6337 } |
|
6338 else if (root->section==Entry::VARIABLEDOC_SEC) |
|
6339 { |
|
6340 //printf("Documentation for variable %s found\n",root->name.data()); |
|
6341 //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data()); |
|
6342 findMember(rootNav,root->name,FALSE,FALSE); |
|
6343 } |
|
6344 else |
|
6345 { |
|
6346 // skip section |
|
6347 //printf("skip section\n"); |
|
6348 } |
|
6349 } |
|
6350 |
|
6351 static void findMemberDocumentation(EntryNav *rootNav) |
|
6352 { |
|
6353 if (rootNav->section()==Entry::MEMBERDOC_SEC || |
|
6354 rootNav->section()==Entry::OVERLOADDOC_SEC || |
|
6355 rootNav->section()==Entry::FUNCTION_SEC || |
|
6356 rootNav->section()==Entry::VARIABLE_SEC || |
|
6357 rootNav->section()==Entry::VARIABLEDOC_SEC || |
|
6358 rootNav->section()==Entry::DEFINE_SEC |
|
6359 ) |
|
6360 { |
|
6361 rootNav->loadEntry(g_storage); |
|
6362 |
|
6363 filterMemberDocumentation(rootNav); |
|
6364 |
|
6365 rootNav->releaseEntry(); |
|
6366 } |
|
6367 if (rootNav->children()) |
|
6368 { |
|
6369 EntryNavListIterator eli(*rootNav->children()); |
|
6370 EntryNav *e; |
|
6371 for (;(e=eli.current());++eli) |
|
6372 { |
|
6373 if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e); |
|
6374 } |
|
6375 } |
|
6376 } |
|
6377 |
|
6378 //---------------------------------------------------------------------- |
|
6379 |
|
6380 static void findObjCMethodDefinitions(EntryNav *rootNav) |
|
6381 { |
|
6382 if (rootNav->children()) |
|
6383 { |
|
6384 EntryNavListIterator eli(*rootNav->children()); |
|
6385 EntryNav *objCImplNav; |
|
6386 for (;(objCImplNav=eli.current());++eli) |
|
6387 { |
|
6388 if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children()) |
|
6389 { |
|
6390 EntryNavListIterator seli(*objCImplNav->children()); |
|
6391 EntryNav *objCMethodNav; |
|
6392 for (;(objCMethodNav=seli.current());++seli) |
|
6393 { |
|
6394 if (objCMethodNav->section()==Entry::FUNCTION_SEC) |
|
6395 { |
|
6396 objCMethodNav->loadEntry(g_storage); |
|
6397 Entry *objCMethod = objCMethodNav->entry(); |
|
6398 |
|
6399 //Printf(" Found ObjC method definition %s\n",objCMethod->name.data()); |
|
6400 findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+ |
|
6401 objCMethod->name+" "+objCMethod->args, FALSE,TRUE); |
|
6402 objCMethod->section=Entry::EMPTY_SEC; |
|
6403 |
|
6404 objCMethodNav->releaseEntry(); |
|
6405 } |
|
6406 } |
|
6407 } |
|
6408 } |
|
6409 } |
|
6410 } |
|
6411 |
|
6412 //---------------------------------------------------------------------- |
|
6413 // find and add the enumeration to their classes, namespaces or files |
|
6414 |
|
6415 static void findEnums(EntryNav *rootNav) |
|
6416 { |
|
6417 if (rootNav->section()==Entry::ENUM_SEC) |
|
6418 // non anonymous enumeration |
|
6419 { |
|
6420 rootNav->loadEntry(g_storage); |
|
6421 Entry *root = rootNav->entry(); |
|
6422 |
|
6423 MemberDef *md=0; |
|
6424 ClassDef *cd=0; |
|
6425 FileDef *fd=0; |
|
6426 NamespaceDef *nd=0; |
|
6427 MemberNameSDict *mnsd=0; |
|
6428 bool isGlobal; |
|
6429 bool isRelated=FALSE; |
|
6430 bool isMemberOf=FALSE; |
|
6431 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data()); |
|
6432 int i; |
|
6433 |
|
6434 QCString name; |
|
6435 QCString scope; |
|
6436 |
|
6437 if ((i=root->name.findRev("::"))!=-1) // scope is specified |
|
6438 { |
|
6439 scope=root->name.left(i); // extract scope |
|
6440 name=root->name.right(root->name.length()-i-2); // extract name |
|
6441 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); |
|
6442 } |
|
6443 else // no scope, check the scope in which the docs where found |
|
6444 { |
|
6445 if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) |
|
6446 && !rootNav->parent()->name().isEmpty() |
|
6447 ) // found enum docs inside a compound |
|
6448 { |
|
6449 scope=rootNav->parent()->name(); |
|
6450 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); |
|
6451 } |
|
6452 name=root->name; |
|
6453 } |
|
6454 |
|
6455 if (!root->relates.isEmpty()) |
|
6456 { // related member, prefix user specified scope |
|
6457 isRelated=TRUE; |
|
6458 isMemberOf=(root->relatesType == MemberOf); |
|
6459 if (getClass(root->relates)==0 && !scope.isEmpty()) |
|
6460 scope=mergeScopes(scope,root->relates); |
|
6461 else |
|
6462 scope=root->relates.copy(); |
|
6463 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); |
|
6464 } |
|
6465 |
|
6466 if (cd && !name.isEmpty()) // found a enum inside a compound |
|
6467 { |
|
6468 //printf("Enum `%s'::`%s'\n",cd->name(),name.data()); |
|
6469 fd=0; |
|
6470 mnsd=Doxygen::memberNameSDict; |
|
6471 isGlobal=FALSE; |
|
6472 } |
|
6473 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace |
|
6474 { |
|
6475 mnsd=Doxygen::functionNameSDict; |
|
6476 isGlobal=TRUE; |
|
6477 } |
|
6478 else // found a global enum |
|
6479 { |
|
6480 fd=rootNav->fileDef(); |
|
6481 mnsd=Doxygen::functionNameSDict; |
|
6482 isGlobal=TRUE; |
|
6483 } |
|
6484 |
|
6485 if (!name.isEmpty()) |
|
6486 { |
|
6487 // new enum type |
|
6488 md = new MemberDef( |
|
6489 root->fileName,root->startLine, |
|
6490 0,name,0,0, |
|
6491 root->protection,Normal,FALSE, |
|
6492 isMemberOf ? Foreign : isRelated ? Related : Member, |
|
6493 MemberDef::Enumeration, |
|
6494 0,0); |
|
6495 md->setTagInfo(rootNav->tagInfo()); |
|
6496 if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd); |
|
6497 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
6498 md->setBodyDef(rootNav->fileDef()); |
|
6499 //printf("Enum %s definition at line %d of %s: protection=%d\n", |
|
6500 // root->name.data(),root->bodyLine,root->fileName.data(),root->protection); |
|
6501 md->addSectionsToDefinition(root->anchors); |
|
6502 md->setMemberGroupId(root->mGrpId); |
|
6503 md->enableCallGraph(root->callGraph); |
|
6504 md->enableCallerGraph(root->callerGraph); |
|
6505 //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1); |
|
6506 md->setRefItems(root->sli); |
|
6507 //printf("found enum %s nd=%p\n",name.data(),nd); |
|
6508 bool defSet=FALSE; |
|
6509 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') |
|
6510 { |
|
6511 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES")) |
|
6512 { |
|
6513 md->setDefinition(name); |
|
6514 } |
|
6515 else |
|
6516 { |
|
6517 md->setDefinition(nd->name()+"::"+name); |
|
6518 } |
|
6519 //printf("definition=%s\n",md->definition()); |
|
6520 defSet=TRUE; |
|
6521 md->setNamespace(nd); |
|
6522 nd->insertMember(md); |
|
6523 } |
|
6524 |
|
6525 // even if we have already added the enum to a namespace, we still |
|
6526 // also want to add it to other appropriate places such as file |
|
6527 // or class. |
|
6528 if (isGlobal) |
|
6529 { |
|
6530 if (!defSet) md->setDefinition(name); |
|
6531 if (fd==0 && rootNav->parent()) |
|
6532 { |
|
6533 fd=rootNav->parent()->fileDef(); |
|
6534 } |
|
6535 if (fd) |
|
6536 { |
|
6537 md->setFileDef(fd); |
|
6538 fd->insertMember(md); |
|
6539 } |
|
6540 } |
|
6541 else if (cd) |
|
6542 { |
|
6543 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES")) |
|
6544 { |
|
6545 md->setDefinition(name); |
|
6546 } |
|
6547 else |
|
6548 { |
|
6549 md->setDefinition(cd->name()+"::"+name); |
|
6550 } |
|
6551 cd->insertMember(md); |
|
6552 cd->insertUsedFile(root->fileName); |
|
6553 } |
|
6554 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
6555 md->setDocsForDefinition(!root->proto); |
|
6556 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
6557 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
6558 |
|
6559 //printf("Adding member=%s\n",md->name().data()); |
|
6560 MemberName *mn; |
|
6561 if ((mn=(*mnsd)[name])) |
|
6562 { |
|
6563 // this is used if the same enum is in multiple namespaces/classes |
|
6564 mn->append(md); |
|
6565 } |
|
6566 else // new enum name |
|
6567 { |
|
6568 mn = new MemberName(name); |
|
6569 mn->append(md); |
|
6570 mnsd->append(name,mn); |
|
6571 //printf("add %s to new memberName. Now %d members\n", |
|
6572 // name.data(),mn->count()); |
|
6573 } |
|
6574 addMemberToGroups(root,md); |
|
6575 |
|
6576 #if 0 |
|
6577 if (rootNav->children()) |
|
6578 { |
|
6579 EntryNavListIterator eli(*rootNav->children()); |
|
6580 EntryNav *e; |
|
6581 for (;(e=eli.current());++eli) |
|
6582 { |
|
6583 //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated); |
|
6584 MemberName *fmn=0; |
|
6585 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd; |
|
6586 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) |
|
6587 // get list of members with the same name as the field |
|
6588 { |
|
6589 MemberNameIterator fmni(*fmn); |
|
6590 MemberDef *fmd; |
|
6591 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) |
|
6592 { |
|
6593 if (fmd->isEnumValue()) |
|
6594 { |
|
6595 //printf("found enum value with same name\n"); |
|
6596 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') |
|
6597 { |
|
6598 NamespaceDef *fnd=fmd->getNamespaceDef(); |
|
6599 if (fnd==nd) // enum value is inside a namespace |
|
6600 { |
|
6601 md->insertEnumField(fmd); |
|
6602 fmd->setEnumScope(md); |
|
6603 } |
|
6604 } |
|
6605 else if (isGlobal) |
|
6606 { |
|
6607 FileDef *ffd=fmd->getFileDef(); |
|
6608 if (ffd==fd) // enum value has file scope |
|
6609 { |
|
6610 md->insertEnumField(fmd); |
|
6611 fmd->setEnumScope(md); |
|
6612 } |
|
6613 } |
|
6614 else if (isRelated && cd) // reparent enum value to |
|
6615 // match the enum's scope |
|
6616 { |
|
6617 md->insertEnumField(fmd); // add field def to list |
|
6618 fmd->setEnumScope(md); // cross ref with enum name |
|
6619 fmd->setEnumClassScope(cd); // cross ref with enum name |
|
6620 fmd->setOuterScope(cd); |
|
6621 fmd->makeRelated(); |
|
6622 cd->insertMember(fmd); |
|
6623 } |
|
6624 else |
|
6625 { |
|
6626 ClassDef *fcd=fmd->getClassDef(); |
|
6627 if (fcd==cd) // enum value is inside a class |
|
6628 { |
|
6629 //printf("Inserting enum field %s in enum scope %s\n", |
|
6630 // fmd->name().data(),md->name().data()); |
|
6631 md->insertEnumField(fmd); // add field def to list |
|
6632 fmd->setEnumScope(md); // cross ref with enum name |
|
6633 } |
|
6634 } |
|
6635 } |
|
6636 } |
|
6637 } |
|
6638 } |
|
6639 } |
|
6640 #endif |
|
6641 } |
|
6642 |
|
6643 rootNav->releaseEntry(); |
|
6644 } |
|
6645 else |
|
6646 { |
|
6647 RECURSE_ENTRYTREE(findEnums,rootNav); |
|
6648 } |
|
6649 } |
|
6650 |
|
6651 //---------------------------------------------------------------------- |
|
6652 |
|
6653 static void addEnumValuesToEnums(EntryNav *rootNav) |
|
6654 { |
|
6655 if (rootNav->section()==Entry::ENUM_SEC) |
|
6656 // non anonymous enumeration |
|
6657 { |
|
6658 rootNav->loadEntry(g_storage); |
|
6659 Entry *root = rootNav->entry(); |
|
6660 |
|
6661 ClassDef *cd=0; |
|
6662 FileDef *fd=0; |
|
6663 NamespaceDef *nd=0; |
|
6664 MemberNameSDict *mnsd=0; |
|
6665 bool isGlobal; |
|
6666 bool isRelated=FALSE; |
|
6667 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data()); |
|
6668 int i; |
|
6669 |
|
6670 QCString name; |
|
6671 QCString scope; |
|
6672 |
|
6673 if ((i=root->name.findRev("::"))!=-1) // scope is specified |
|
6674 { |
|
6675 scope=root->name.left(i); // extract scope |
|
6676 name=root->name.right(root->name.length()-i-2); // extract name |
|
6677 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); |
|
6678 } |
|
6679 else // no scope, check the scope in which the docs where found |
|
6680 { |
|
6681 if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) |
|
6682 && !rootNav->parent()->name().isEmpty() |
|
6683 ) // found enum docs inside a compound |
|
6684 { |
|
6685 scope=rootNav->parent()->name(); |
|
6686 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); |
|
6687 } |
|
6688 name=root->name; |
|
6689 } |
|
6690 |
|
6691 if (!root->relates.isEmpty()) |
|
6692 { // related member, prefix user specified scope |
|
6693 isRelated=TRUE; |
|
6694 if (getClass(root->relates)==0 && !scope.isEmpty()) |
|
6695 scope=mergeScopes(scope,root->relates); |
|
6696 else |
|
6697 scope=root->relates.copy(); |
|
6698 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope); |
|
6699 } |
|
6700 |
|
6701 if (cd && !name.isEmpty()) // found a enum inside a compound |
|
6702 { |
|
6703 //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data()); |
|
6704 fd=0; |
|
6705 mnsd=Doxygen::memberNameSDict; |
|
6706 isGlobal=FALSE; |
|
6707 } |
|
6708 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace |
|
6709 { |
|
6710 //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data()); |
|
6711 mnsd=Doxygen::functionNameSDict; |
|
6712 isGlobal=TRUE; |
|
6713 } |
|
6714 else // found a global enum |
|
6715 { |
|
6716 fd=rootNav->fileDef(); |
|
6717 //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data()); |
|
6718 mnsd=Doxygen::functionNameSDict; |
|
6719 isGlobal=TRUE; |
|
6720 } |
|
6721 |
|
6722 if (!name.isEmpty()) |
|
6723 { |
|
6724 MemberName *mn = mnsd->find(name); // for all members with this name |
|
6725 if (mn) |
|
6726 { |
|
6727 MemberNameIterator mni(*mn); |
|
6728 MemberDef *md; |
|
6729 for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list |
|
6730 { |
|
6731 if (md->isEnumerate() && rootNav->children()) |
|
6732 { |
|
6733 EntryNavListIterator eli(*rootNav->children()); // for each enum value |
|
6734 EntryNav *e; |
|
6735 for (;(e=eli.current());++eli) |
|
6736 { |
|
6737 SrcLangExt sle; |
|
6738 if (rootNav->fileDef() && |
|
6739 ( (sle=getLanguageFromFileName(rootNav->fileDef()->name()))==SrcLangExt_CSharp |
|
6740 || sle==SrcLangExt_Java || sle==SrcLangExt_XML |
|
6741 ) |
|
6742 ) |
|
6743 { |
|
6744 // Unlike C++, for C# enum value are only inside the enum |
|
6745 // scope, so we must create them here and only add them to the |
|
6746 // enum |
|
6747 e->loadEntry(g_storage); |
|
6748 Entry *root = e->entry(); |
|
6749 if (md->qualifiedName()==rootNav->name()) // enum value scope matches that of the enum |
|
6750 { |
|
6751 MemberDef *fmd=new MemberDef( |
|
6752 root->fileName,root->startLine, |
|
6753 root->type,root->name,root->args,0, |
|
6754 Public, Normal,root->stat,Member, |
|
6755 MemberDef::EnumValue,0,0); |
|
6756 if (md->getClassDef()) fmd->setMemberClass(md->getClassDef()); |
|
6757 else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef()); |
|
6758 else if (md->getFileDef()) fmd->setFileDef(md->getFileDef()); |
|
6759 fmd->setOuterScope(md->getOuterScope()); |
|
6760 fmd->setTagInfo(e->tagInfo()); |
|
6761 fmd->setDocumentation(root->doc,root->docFile,root->docLine); |
|
6762 fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
6763 fmd->addSectionsToDefinition(root->anchors); |
|
6764 fmd->setInitializer(root->initializer); |
|
6765 fmd->setMaxInitLines(root->initLines); |
|
6766 fmd->setMemberGroupId(root->mGrpId); |
|
6767 fmd->setExplicitExternal(root->explicitExternal); |
|
6768 if (fmd) |
|
6769 { |
|
6770 md->insertEnumField(fmd); |
|
6771 fmd->setEnumScope(md); |
|
6772 } |
|
6773 } |
|
6774 e->releaseEntry(); |
|
6775 } |
|
6776 else |
|
6777 { |
|
6778 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated); |
|
6779 MemberName *fmn=0; |
|
6780 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd; |
|
6781 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) |
|
6782 // get list of members with the same name as the field |
|
6783 { |
|
6784 MemberNameIterator fmni(*fmn); |
|
6785 MemberDef *fmd; |
|
6786 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) |
|
6787 { |
|
6788 if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope |
|
6789 { |
|
6790 //printf("found enum value with same name %s in scope %s\n", |
|
6791 // fmd->name().data(),fmd->getOuterScope()->name().data()); |
|
6792 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') |
|
6793 { |
|
6794 NamespaceDef *fnd=fmd->getNamespaceDef(); |
|
6795 if (fnd==nd) // enum value is inside a namespace |
|
6796 { |
|
6797 md->insertEnumField(fmd); |
|
6798 fmd->setEnumScope(md); |
|
6799 } |
|
6800 } |
|
6801 else if (isGlobal) |
|
6802 { |
|
6803 FileDef *ffd=fmd->getFileDef(); |
|
6804 if (ffd==fd) // enum value has file scope |
|
6805 { |
|
6806 md->insertEnumField(fmd); |
|
6807 fmd->setEnumScope(md); |
|
6808 } |
|
6809 } |
|
6810 else if (isRelated && cd) // reparent enum value to |
|
6811 // match the enum's scope |
|
6812 { |
|
6813 md->insertEnumField(fmd); // add field def to list |
|
6814 fmd->setEnumScope(md); // cross ref with enum name |
|
6815 fmd->setEnumClassScope(cd); // cross ref with enum name |
|
6816 fmd->setOuterScope(cd); |
|
6817 fmd->makeRelated(); |
|
6818 cd->insertMember(fmd); |
|
6819 } |
|
6820 else |
|
6821 { |
|
6822 ClassDef *fcd=fmd->getClassDef(); |
|
6823 if (fcd==cd) // enum value is inside a class |
|
6824 { |
|
6825 //printf("Inserting enum field %s in enum scope %s\n", |
|
6826 // fmd->name().data(),md->name().data()); |
|
6827 md->insertEnumField(fmd); // add field def to list |
|
6828 fmd->setEnumScope(md); // cross ref with enum name |
|
6829 } |
|
6830 } |
|
6831 } |
|
6832 } |
|
6833 } |
|
6834 } |
|
6835 } |
|
6836 } |
|
6837 } |
|
6838 } |
|
6839 } |
|
6840 |
|
6841 rootNav->releaseEntry(); |
|
6842 } |
|
6843 else |
|
6844 { |
|
6845 RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav); |
|
6846 } |
|
6847 } |
|
6848 |
|
6849 |
|
6850 //---------------------------------------------------------------------- |
|
6851 // find the documentation blocks for the enumerations |
|
6852 |
|
6853 static void findEnumDocumentation(EntryNav *rootNav) |
|
6854 { |
|
6855 if (rootNav->section()==Entry::ENUMDOC_SEC |
|
6856 && !rootNav->name().isEmpty() |
|
6857 && rootNav->name().at(0)!='@' // skip anonymous enums |
|
6858 ) |
|
6859 { |
|
6860 rootNav->loadEntry(g_storage); |
|
6861 Entry *root = rootNav->entry(); |
|
6862 |
|
6863 //printf("Found docs for enum with name `%s' in context %s\n", |
|
6864 // root->name.data(),root->parent->name.data()); |
|
6865 int i; |
|
6866 QCString name; |
|
6867 QCString scope; |
|
6868 if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name |
|
6869 { |
|
6870 name=root->name.right(root->name.length()-i-2); // extract name |
|
6871 scope=root->name.left(i); // extract scope |
|
6872 //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data()); |
|
6873 } |
|
6874 else // just the name |
|
6875 { |
|
6876 name=root->name; |
|
6877 } |
|
6878 if (( rootNav->parent()->section() & Entry::SCOPE_MASK ) |
|
6879 && !rootNav->parent()->name().isEmpty() |
|
6880 ) // found enum docs inside a compound |
|
6881 { |
|
6882 if (!scope.isEmpty()) scope.prepend("::"); |
|
6883 scope.prepend(rootNav->parent()->name()); |
|
6884 } |
|
6885 ClassDef *cd=getClass(scope); |
|
6886 |
|
6887 if (!name.isEmpty()) |
|
6888 { |
|
6889 bool found=FALSE; |
|
6890 if (cd) |
|
6891 { |
|
6892 //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data()); |
|
6893 QCString className=cd->name().copy(); |
|
6894 MemberName *mn=Doxygen::memberNameSDict->find(name); |
|
6895 if (mn) |
|
6896 { |
|
6897 MemberNameIterator mni(*mn); |
|
6898 MemberDef *md; |
|
6899 for (mni.toFirst();(md=mni.current()) && !found;++mni) |
|
6900 { |
|
6901 ClassDef *cd=md->getClassDef(); |
|
6902 if (cd && cd->name()==className && md->isEnumerate()) |
|
6903 { |
|
6904 // documentation outside a compound overrides the documentation inside it |
|
6905 #if 0 |
|
6906 if (!md->documentation() || rootNav->parent()->name().isEmpty()) |
|
6907 #endif |
|
6908 { |
|
6909 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
6910 md->setDocsForDefinition(!root->proto); |
|
6911 } |
|
6912 |
|
6913 // brief descriptions inside a compound override the documentation |
|
6914 // outside it |
|
6915 #if 0 |
|
6916 if (!md->briefDescription() || !rootNav->parent()->name().isEmpty()) |
|
6917 #endif |
|
6918 { |
|
6919 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
6920 } |
|
6921 |
|
6922 if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty()) |
|
6923 { |
|
6924 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
6925 } |
|
6926 |
|
6927 if (root->mGrpId!=-1 && md->getMemberGroupId()==-1) |
|
6928 { |
|
6929 md->setMemberGroupId(root->mGrpId); |
|
6930 } |
|
6931 |
|
6932 md->addSectionsToDefinition(root->anchors); |
|
6933 md->setRefItems(root->sli); |
|
6934 |
|
6935 GroupDef *gd=md->getGroupDef(); |
|
6936 if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is |
|
6937 { |
|
6938 addMemberToGroups(root,md); |
|
6939 } |
|
6940 |
|
6941 found=TRUE; |
|
6942 } |
|
6943 } |
|
6944 } |
|
6945 else |
|
6946 { |
|
6947 //printf("MemberName %s not found!\n",name.data()); |
|
6948 } |
|
6949 } |
|
6950 else // enum outside class |
|
6951 { |
|
6952 //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId); |
|
6953 MemberName *mn=Doxygen::functionNameSDict->find(name); |
|
6954 if (mn) |
|
6955 { |
|
6956 MemberNameIterator mni(*mn); |
|
6957 MemberDef *md; |
|
6958 for (mni.toFirst();(md=mni.current()) && !found;++mni) |
|
6959 { |
|
6960 if (md->isEnumerate()) |
|
6961 { |
|
6962 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
6963 md->setDocsForDefinition(!root->proto); |
|
6964 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
6965 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
6966 md->addSectionsToDefinition(root->anchors); |
|
6967 md->setMemberGroupId(root->mGrpId); |
|
6968 |
|
6969 GroupDef *gd=md->getGroupDef(); |
|
6970 if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is |
|
6971 { |
|
6972 addMemberToGroups(root,md); |
|
6973 } |
|
6974 |
|
6975 found=TRUE; |
|
6976 } |
|
6977 } |
|
6978 } |
|
6979 } |
|
6980 if (!found) |
|
6981 { |
|
6982 warn(root->fileName,root->startLine, |
|
6983 "Warning: Documentation for undefined enum `%s' found.", |
|
6984 name.data() |
|
6985 ); |
|
6986 } |
|
6987 } |
|
6988 |
|
6989 rootNav->releaseEntry(); |
|
6990 } |
|
6991 RECURSE_ENTRYTREE(findEnumDocumentation,rootNav); |
|
6992 } |
|
6993 |
|
6994 // seach for each enum (member or function) in mnl if it has documented |
|
6995 // enum values. |
|
6996 static void findDEV(const MemberNameSDict &mnsd) |
|
6997 { |
|
6998 MemberName *mn; |
|
6999 MemberNameSDict::Iterator mnli(mnsd); |
|
7000 // for each member name |
|
7001 for (mnli.toFirst();(mn=mnli.current());++mnli) |
|
7002 { |
|
7003 MemberDef *md; |
|
7004 MemberNameIterator mni(*mn); |
|
7005 // for each member definition |
|
7006 for (mni.toFirst();(md=mni.current());++mni) |
|
7007 { |
|
7008 if (md->isEnumerate()) // member is an enum |
|
7009 { |
|
7010 LockingPtr<MemberList> fmdl = md->enumFieldList(); |
|
7011 int documentedEnumValues=0; |
|
7012 if (fmdl!=0) // enum has values |
|
7013 { |
|
7014 MemberListIterator fmni(*fmdl); |
|
7015 MemberDef *fmd; |
|
7016 // for each enum value |
|
7017 for (fmni.toFirst();(fmd=fmni.current());++fmni) |
|
7018 { |
|
7019 if (fmd->isLinkableInProject()) documentedEnumValues++; |
|
7020 } |
|
7021 } |
|
7022 // at least one enum value is documented |
|
7023 if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE); |
|
7024 } |
|
7025 } |
|
7026 } |
|
7027 } |
|
7028 |
|
7029 // seach for each enum (member or function) if it has documented enum |
|
7030 // values. |
|
7031 static void findDocumentedEnumValues() |
|
7032 { |
|
7033 findDEV(*Doxygen::memberNameSDict); |
|
7034 findDEV(*Doxygen::functionNameSDict); |
|
7035 } |
|
7036 |
|
7037 //---------------------------------------------------------------------- |
|
7038 |
|
7039 static void addMembersToIndex() |
|
7040 { |
|
7041 MemberName *mn; |
|
7042 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); |
|
7043 // for each member name |
|
7044 for (mnli.toFirst();(mn=mnli.current());++mnli) |
|
7045 { |
|
7046 MemberDef *md; |
|
7047 MemberNameIterator mni(*mn); |
|
7048 // for each member definition |
|
7049 for (mni.toFirst();(md=mni.current());++mni) |
|
7050 { |
|
7051 addClassMemberNameToIndex(md); |
|
7052 } |
|
7053 } |
|
7054 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); |
|
7055 // for each member name |
|
7056 for (fnli.toFirst();(mn=fnli.current());++fnli) |
|
7057 { |
|
7058 MemberDef *md; |
|
7059 MemberNameIterator mni(*mn); |
|
7060 // for each member definition |
|
7061 for (mni.toFirst();(md=mni.current());++mni) |
|
7062 { |
|
7063 if (md->getNamespaceDef()) |
|
7064 { |
|
7065 addNamespaceMemberNameToIndex(md); |
|
7066 } |
|
7067 else |
|
7068 { |
|
7069 addFileMemberNameToIndex(md); |
|
7070 } |
|
7071 } |
|
7072 } |
|
7073 } |
|
7074 |
|
7075 //---------------------------------------------------------------------- |
|
7076 // computes the relation between all members. For each member `m' |
|
7077 // the members that override the implementation of `m' are searched and |
|
7078 // the member that `m' overrides is searched. |
|
7079 |
|
7080 static void computeMemberRelations() |
|
7081 { |
|
7082 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); |
|
7083 MemberName *mn; |
|
7084 for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name |
|
7085 { |
|
7086 MemberNameIterator mdi(*mn); |
|
7087 MemberDef *md; |
|
7088 for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name |
|
7089 { |
|
7090 MemberDef *bmd = mn->first(); // for each other member with the same name |
|
7091 while (bmd) |
|
7092 { |
|
7093 ClassDef *mcd = md->getClassDef(); |
|
7094 if (mcd && mcd->baseClasses()) |
|
7095 { |
|
7096 ClassDef *bmcd = bmd->getClassDef(); |
|
7097 //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n", |
|
7098 // mcd->name().data(),md->name().data(),md, |
|
7099 // bmcd->name().data(),bmd->name().data(),bmd |
|
7100 // ); |
|
7101 if (md!=bmd && bmcd && mcd && bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE)) |
|
7102 { |
|
7103 LockingPtr<ArgumentList> bmdAl = bmd->argumentList(); |
|
7104 LockingPtr<ArgumentList> mdAl = md->argumentList(); |
|
7105 //printf(" Base argList=`%s'\n Super argList=`%s'\n", |
|
7106 // argListToString(bmdAl.pointer()).data(), |
|
7107 // argListToString(mdAl.pointer()).data() |
|
7108 // ); |
|
7109 if ( |
|
7110 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(), |
|
7111 md->getOuterScope(), md->getFileDef(), mdAl.pointer(), |
|
7112 TRUE |
|
7113 ) |
|
7114 ) |
|
7115 { |
|
7116 //printf(" match found!\n"); |
|
7117 if (mcd && bmcd && |
|
7118 mcd->isLinkable() && bmcd->isLinkable() |
|
7119 ) |
|
7120 { |
|
7121 MemberDef *rmd; |
|
7122 if ((rmd=md->reimplements())==0 || |
|
7123 minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef()) |
|
7124 ) |
|
7125 { |
|
7126 //printf("setting (new) reimplements member\n"); |
|
7127 md->setReimplements(bmd); |
|
7128 } |
|
7129 //printf("%s: add reimplements member %s\n",mcd->name().data(),bmcd->name().data()); |
|
7130 //md->setImplements(bmd); |
|
7131 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data()); |
|
7132 bmd->insertReimplementedBy(md); |
|
7133 } |
|
7134 } |
|
7135 } |
|
7136 } |
|
7137 bmd = mn->next(); |
|
7138 } |
|
7139 } |
|
7140 } |
|
7141 } |
|
7142 |
|
7143 |
|
7144 //---------------------------------------------------------------------------- |
|
7145 //static void computeClassImplUsageRelations() |
|
7146 //{ |
|
7147 // ClassDef *cd; |
|
7148 // ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
7149 // for (;(cd=cli.current());++cli) |
|
7150 // { |
|
7151 // cd->determineImplUsageRelation(); |
|
7152 // } |
|
7153 //} |
|
7154 |
|
7155 //---------------------------------------------------------------------------- |
|
7156 |
|
7157 static void createTemplateInstanceMembers() |
|
7158 { |
|
7159 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
7160 ClassDef *cd; |
|
7161 // for each class |
|
7162 for (cli.toFirst();(cd=cli.current());++cli) |
|
7163 { |
|
7164 // that is a template |
|
7165 QDict<ClassDef> *templInstances = cd->getTemplateInstances(); |
|
7166 if (templInstances) |
|
7167 { |
|
7168 QDictIterator<ClassDef> qdi(*templInstances); |
|
7169 ClassDef *tcd=0; |
|
7170 // for each instance of the template |
|
7171 for (qdi.toFirst();(tcd=qdi.current());++qdi) |
|
7172 { |
|
7173 tcd->addMembersToTemplateInstance(cd,qdi.currentKey()); |
|
7174 } |
|
7175 } |
|
7176 } |
|
7177 } |
|
7178 |
|
7179 //---------------------------------------------------------------------------- |
|
7180 |
|
7181 // builds the list of all members for each class |
|
7182 |
|
7183 static void buildCompleteMemberLists() |
|
7184 { |
|
7185 ClassDef *cd; |
|
7186 // merge members of categories into the class they extend |
|
7187 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
7188 for (cli.toFirst();(cd=cli.current());++cli) |
|
7189 { |
|
7190 int i=cd->name().find('('); |
|
7191 if (i!=-1) // it is an Objective-C category |
|
7192 { |
|
7193 QCString baseName=cd->name().left(i); |
|
7194 ClassDef *baseClass=Doxygen::classSDict->find(baseName); |
|
7195 if (baseClass) |
|
7196 { |
|
7197 //printf("*** merging members of category %s into %s\n", |
|
7198 // cd->name().data(),baseClass->name().data()); |
|
7199 baseClass->mergeCategory(cd); |
|
7200 } |
|
7201 } |
|
7202 } |
|
7203 // merge the member list of base classes into the inherited classes. |
|
7204 for (cli.toFirst();(cd=cli.current());++cli) |
|
7205 { |
|
7206 if (// !cd->isReference() && // not an external class |
|
7207 cd->subClasses()==0 && // is a root of the hierarchy |
|
7208 cd->baseClasses()) // and has at least one base class |
|
7209 { |
|
7210 //printf("*** merging members for %s\n",cd->name().data()); |
|
7211 cd->mergeMembers(); |
|
7212 } |
|
7213 } |
|
7214 // now sort the member list of all classes. |
|
7215 for (cli.toFirst();(cd=cli.current());++cli) |
|
7216 { |
|
7217 if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort(); |
|
7218 } |
|
7219 } |
|
7220 |
|
7221 //---------------------------------------------------------------------------- |
|
7222 |
|
7223 static void generateFileSources() |
|
7224 { |
|
7225 if (documentedHtmlFiles==0) return; |
|
7226 if (Doxygen::inputNameList->count()>0) |
|
7227 { |
|
7228 FileNameListIterator fnli(*Doxygen::inputNameList); |
|
7229 FileName *fn; |
|
7230 for (;(fn=fnli.current());++fnli) |
|
7231 { |
|
7232 FileNameIterator fni(*fn); |
|
7233 FileDef *fd; |
|
7234 for (;(fd=fni.current());++fni) |
|
7235 { |
|
7236 if (fd->generateSourceFile()) // sources need to be shown in the output |
|
7237 { |
|
7238 msg("Generating code for file %s...\n",fd->docName().data()); |
|
7239 fd->writeSource(*g_outputList); |
|
7240 } |
|
7241 else if (!fd->isReference() && Doxygen::parseSourcesNeeded) |
|
7242 // we needed to parse the sources even if we do not show them |
|
7243 { |
|
7244 msg("Parsing code for file %s...\n",fd->docName().data()); |
|
7245 fd->parseSource(); |
|
7246 } |
|
7247 } |
|
7248 } |
|
7249 } |
|
7250 } |
|
7251 |
|
7252 //---------------------------------------------------------------------------- |
|
7253 |
|
7254 static void generateFileDocs() |
|
7255 { |
|
7256 if (documentedHtmlFiles==0) return; |
|
7257 |
|
7258 if (Doxygen::inputNameList->count()>0) |
|
7259 { |
|
7260 FileNameListIterator fnli(*Doxygen::inputNameList); |
|
7261 FileName *fn; |
|
7262 for (fnli.toFirst();(fn=fnli.current());++fnli) |
|
7263 { |
|
7264 FileNameIterator fni(*fn); |
|
7265 FileDef *fd; |
|
7266 for (fni.toFirst();(fd=fni.current());++fni) |
|
7267 { |
|
7268 bool doc = fd->isLinkableInProject(); |
|
7269 if (doc) |
|
7270 { |
|
7271 msg("Generating docs for file %s...\n",fd->docName().data()); |
|
7272 fd->writeDocumentation(*g_outputList); |
|
7273 } |
|
7274 } |
|
7275 } |
|
7276 } |
|
7277 } |
|
7278 |
|
7279 //---------------------------------------------------------------------------- |
|
7280 |
|
7281 static void addSourceReferences() |
|
7282 { |
|
7283 // add source references for class definitions |
|
7284 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
7285 ClassDef *cd=0; |
|
7286 for (cli.toFirst();(cd=cli.current());++cli) |
|
7287 { |
|
7288 FileDef *fd=cd->getBodyDef(); |
|
7289 if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1) |
|
7290 { |
|
7291 fd->addSourceRef(cd->getStartBodyLine(),cd,0); |
|
7292 } |
|
7293 } |
|
7294 // add source references for namespace definitions |
|
7295 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); |
|
7296 NamespaceDef *nd=0; |
|
7297 for (nli.toFirst();(nd=nli.current());++nli) |
|
7298 { |
|
7299 FileDef *fd=nd->getBodyDef(); |
|
7300 if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1) |
|
7301 { |
|
7302 fd->addSourceRef(nd->getStartBodyLine(),nd,0); |
|
7303 } |
|
7304 } |
|
7305 |
|
7306 // add source references for member names |
|
7307 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); |
|
7308 MemberName *mn=0; |
|
7309 for (mnli.toFirst();(mn=mnli.current());++mnli) |
|
7310 { |
|
7311 MemberNameIterator mni(*mn); |
|
7312 MemberDef *md=0; |
|
7313 for (mni.toFirst();(md=mni.current());++mni) |
|
7314 { |
|
7315 //printf("class member %s\n",md->name().data()); |
|
7316 FileDef *fd=md->getBodyDef(); |
|
7317 if (fd && |
|
7318 md->getStartBodyLine()!=-1 && |
|
7319 md->isLinkableInProject() && |
|
7320 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded) |
|
7321 ) |
|
7322 { |
|
7323 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n", |
|
7324 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); |
|
7325 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md); |
|
7326 } |
|
7327 } |
|
7328 } |
|
7329 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); |
|
7330 for (fnli.toFirst();(mn=fnli.current());++fnli) |
|
7331 { |
|
7332 MemberNameIterator mni(*mn); |
|
7333 MemberDef *md=0; |
|
7334 for (mni.toFirst();(md=mni.current());++mni) |
|
7335 { |
|
7336 FileDef *fd=md->getBodyDef(); |
|
7337 //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n", |
|
7338 // md->name().data(), |
|
7339 // md->getStartBodyLine(),md->getEndBodyLine(),fd, |
|
7340 // md->isLinkableInProject(), |
|
7341 // Doxygen::parseSourcesNeeded); |
|
7342 if (fd && |
|
7343 md->getStartBodyLine()!=-1 && |
|
7344 md->isLinkableInProject() && |
|
7345 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded) |
|
7346 ) |
|
7347 { |
|
7348 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n", |
|
7349 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); |
|
7350 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md); |
|
7351 } |
|
7352 } |
|
7353 } |
|
7354 } |
|
7355 |
|
7356 //---------------------------------------------------------------------------- |
|
7357 // generate the documentation of all classes |
|
7358 |
|
7359 static void generateClassList(ClassSDict &classSDict) |
|
7360 { |
|
7361 ClassSDict::Iterator cli(classSDict); |
|
7362 for ( ; cli.current() ; ++cli ) |
|
7363 { |
|
7364 ClassDef *cd=cli.current(); |
|
7365 |
|
7366 //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope); |
|
7367 if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file |
|
7368 cd->getOuterScope()==Doxygen::globalScope // only look at global classes |
|
7369 ) && !cd->isHidden() |
|
7370 ) |
|
7371 { |
|
7372 // skip external references, anonymous compounds and |
|
7373 // template instances |
|
7374 if ( cd->isLinkableInProject() && cd->templateMaster()==0) |
|
7375 { |
|
7376 msg("Generating docs for compound %s...\n",cd->name().data()); |
|
7377 |
|
7378 cd->writeDocumentation(*g_outputList); |
|
7379 cd->writeMemberList(*g_outputList); |
|
7380 } |
|
7381 // even for undocumented classes, the inner classes can be documented. |
|
7382 cd->writeDocumentationForInnerClasses(*g_outputList); |
|
7383 } |
|
7384 } |
|
7385 } |
|
7386 |
|
7387 static void generateClassDocs() |
|
7388 { |
|
7389 // write the installdox script if necessary |
|
7390 if (Config_getBool("GENERATE_HTML") && |
|
7391 (Config_getList("TAGFILES").count()>0 || |
|
7392 Config_getBool("SEARCHENGINE") |
|
7393 ) |
|
7394 ) |
|
7395 { |
|
7396 writeInstallScript(); |
|
7397 } |
|
7398 |
|
7399 msg("Generating annotated compound index...\n"); |
|
7400 writeAnnotatedIndex(*g_outputList); |
|
7401 |
|
7402 //if (Config_getBool("ALPHABETICAL_INDEX")) |
|
7403 //{ |
|
7404 msg("Generating alphabetical compound index...\n"); |
|
7405 writeAlphabeticalIndex(*g_outputList); |
|
7406 //} |
|
7407 |
|
7408 msg("Generating hierarchical class index...\n"); |
|
7409 writeHierarchicalIndex(*g_outputList); |
|
7410 |
|
7411 msg("Generating member index...\n"); |
|
7412 writeClassMemberIndex(*g_outputList); |
|
7413 |
|
7414 if (Doxygen::exampleSDict->count()>0) |
|
7415 { |
|
7416 msg("Generating example index...\n"); |
|
7417 } |
|
7418 |
|
7419 generateClassList(*Doxygen::classSDict); |
|
7420 generateClassList(*Doxygen::hiddenClasses); |
|
7421 } |
|
7422 |
|
7423 //---------------------------------------------------------------------------- |
|
7424 |
|
7425 static void inheritDocumentation() |
|
7426 { |
|
7427 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); |
|
7428 MemberName *mn; |
|
7429 //int count=0; |
|
7430 for (;(mn=mnli.current());++mnli) |
|
7431 { |
|
7432 MemberNameIterator mni(*mn); |
|
7433 MemberDef *md; |
|
7434 for (;(md=mni.current());++mni) |
|
7435 { |
|
7436 //printf("%04d Member `%s'\n",count++,md->name().data()); |
|
7437 if (md->documentation().isEmpty() && md->briefDescription().isEmpty()) |
|
7438 { // no documentation yet |
|
7439 MemberDef *bmd = md->reimplements(); |
|
7440 while (bmd && bmd->documentation().isEmpty() && |
|
7441 bmd->briefDescription().isEmpty() |
|
7442 ) |
|
7443 { // search up the inheritance tree for a documentation member |
|
7444 //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data()); |
|
7445 bmd = bmd->reimplements(); |
|
7446 } |
|
7447 if (bmd) // copy the documentation from the reimplemented member |
|
7448 { |
|
7449 md->setInheritsDocsFrom(bmd); |
|
7450 md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine()); |
|
7451 md->setDocsForDefinition(bmd->isDocsForDefinition()); |
|
7452 md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine()); |
|
7453 md->copyArgumentNames(bmd); |
|
7454 md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine()); |
|
7455 } |
|
7456 } |
|
7457 } |
|
7458 } |
|
7459 } |
|
7460 |
|
7461 //---------------------------------------------------------------------------- |
|
7462 |
|
7463 static void combineUsingRelations() |
|
7464 { |
|
7465 // for each file |
|
7466 FileNameListIterator fnli(*Doxygen::inputNameList); |
|
7467 FileName *fn; |
|
7468 for (fnli.toFirst();(fn=fnli.current());++fnli) |
|
7469 { |
|
7470 FileNameIterator fni(*fn); |
|
7471 FileDef *fd; |
|
7472 for (fni.toFirst();(fd=fni.current());++fni) |
|
7473 { |
|
7474 fd->visited=FALSE; |
|
7475 } |
|
7476 } |
|
7477 for (fnli.toFirst();(fn=fnli.current());++fnli) |
|
7478 { |
|
7479 FileNameIterator fni(*fn); |
|
7480 FileDef *fd; |
|
7481 for (fni.toFirst();(fd=fni.current());++fni) |
|
7482 { |
|
7483 fd->combineUsingRelations(); |
|
7484 } |
|
7485 } |
|
7486 |
|
7487 // for each namespace |
|
7488 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); |
|
7489 NamespaceDef *nd; |
|
7490 for (nli.toFirst() ; (nd=nli.current()) ; ++nli ) |
|
7491 { |
|
7492 nd->visited=FALSE; |
|
7493 } |
|
7494 for (nli.toFirst() ; (nd=nli.current()) ; ++nli ) |
|
7495 { |
|
7496 nd->combineUsingRelations(); |
|
7497 } |
|
7498 } |
|
7499 |
|
7500 //---------------------------------------------------------------------------- |
|
7501 |
|
7502 static void addMembersToMemberGroup() |
|
7503 { |
|
7504 // for each class |
|
7505 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
7506 ClassDef *cd; |
|
7507 for ( ; (cd=cli.current()) ; ++cli ) |
|
7508 { |
|
7509 cd->addMembersToMemberGroup(); |
|
7510 } |
|
7511 // for each file |
|
7512 FileName *fn=Doxygen::inputNameList->first(); |
|
7513 while (fn) |
|
7514 { |
|
7515 FileDef *fd=fn->first(); |
|
7516 while (fd) |
|
7517 { |
|
7518 fd->addMembersToMemberGroup(); |
|
7519 fd=fn->next(); |
|
7520 } |
|
7521 fn=Doxygen::inputNameList->next(); |
|
7522 } |
|
7523 // for each namespace |
|
7524 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); |
|
7525 NamespaceDef *nd; |
|
7526 for ( ; (nd=nli.current()) ; ++nli ) |
|
7527 { |
|
7528 nd->addMembersToMemberGroup(); |
|
7529 } |
|
7530 // for each group |
|
7531 GroupSDict::Iterator gli(*Doxygen::groupSDict); |
|
7532 GroupDef *gd; |
|
7533 for (gli.toFirst();(gd=gli.current());++gli) |
|
7534 { |
|
7535 gd->addMembersToMemberGroup(); |
|
7536 } |
|
7537 } |
|
7538 |
|
7539 //---------------------------------------------------------------------------- |
|
7540 |
|
7541 static void distributeMemberGroupDocumentation() |
|
7542 { |
|
7543 // for each class |
|
7544 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
7545 ClassDef *cd; |
|
7546 for ( ; (cd=cli.current()) ; ++cli ) |
|
7547 { |
|
7548 cd->distributeMemberGroupDocumentation(); |
|
7549 } |
|
7550 // for each file |
|
7551 FileName *fn=Doxygen::inputNameList->first(); |
|
7552 while (fn) |
|
7553 { |
|
7554 FileDef *fd=fn->first(); |
|
7555 while (fd) |
|
7556 { |
|
7557 fd->distributeMemberGroupDocumentation(); |
|
7558 fd=fn->next(); |
|
7559 } |
|
7560 fn=Doxygen::inputNameList->next(); |
|
7561 } |
|
7562 // for each namespace |
|
7563 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); |
|
7564 NamespaceDef *nd; |
|
7565 for ( ; (nd=nli.current()) ; ++nli ) |
|
7566 { |
|
7567 nd->distributeMemberGroupDocumentation(); |
|
7568 } |
|
7569 // for each group |
|
7570 GroupSDict::Iterator gli(*Doxygen::groupSDict); |
|
7571 GroupDef *gd; |
|
7572 for (gli.toFirst();(gd=gli.current());++gli) |
|
7573 { |
|
7574 gd->distributeMemberGroupDocumentation(); |
|
7575 } |
|
7576 } |
|
7577 |
|
7578 //---------------------------------------------------------------------------- |
|
7579 |
|
7580 static void findSectionsInDocumentation() |
|
7581 { |
|
7582 // for each class |
|
7583 ClassSDict::Iterator cli(*Doxygen::classSDict); |
|
7584 ClassDef *cd; |
|
7585 for ( ; (cd=cli.current()) ; ++cli ) |
|
7586 { |
|
7587 cd->findSectionsInDocumentation(); |
|
7588 } |
|
7589 // for each file |
|
7590 FileName *fn=Doxygen::inputNameList->first(); |
|
7591 while (fn) |
|
7592 { |
|
7593 FileDef *fd=fn->first(); |
|
7594 while (fd) |
|
7595 { |
|
7596 fd->findSectionsInDocumentation(); |
|
7597 fd=fn->next(); |
|
7598 } |
|
7599 fn=Doxygen::inputNameList->next(); |
|
7600 } |
|
7601 // for each namespace |
|
7602 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); |
|
7603 NamespaceDef *nd; |
|
7604 for ( ; (nd=nli.current()) ; ++nli ) |
|
7605 { |
|
7606 nd->findSectionsInDocumentation(); |
|
7607 } |
|
7608 // for each group |
|
7609 GroupSDict::Iterator gli(*Doxygen::groupSDict); |
|
7610 GroupDef *gd; |
|
7611 for (gli.toFirst();(gd=gli.current());++gli) |
|
7612 { |
|
7613 gd->findSectionsInDocumentation(); |
|
7614 } |
|
7615 // for each page |
|
7616 PageSDict::Iterator pdi(*Doxygen::pageSDict); |
|
7617 PageDef *pd=0; |
|
7618 for (pdi.toFirst();(pd=pdi.current());++pdi) |
|
7619 { |
|
7620 pd->findSectionsInDocumentation(); |
|
7621 } |
|
7622 if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation(); |
|
7623 } |
|
7624 |
|
7625 static void flushCachedTemplateRelations() |
|
7626 { |
|
7627 // remove all references to classes from the cache |
|
7628 // as there can be new template instances in the inheritance path |
|
7629 // to this class. Optimization: only remove those classes that |
|
7630 // have inheritance instances as direct or indirect sub classes. |
|
7631 QCacheIterator<LookupInfo> ci(Doxygen::lookupCache); |
|
7632 LookupInfo *li=0; |
|
7633 for (ci.toFirst();(li=ci.current());++ci) |
|
7634 { |
|
7635 if (li->classDef) |
|
7636 { |
|
7637 Doxygen::lookupCache.remove(ci.currentKey()); |
|
7638 } |
|
7639 } |
|
7640 // remove all cached typedef resolutions whose target is a |
|
7641 // template class as this may now be a template instance |
|
7642 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); |
|
7643 MemberName *fn; |
|
7644 for (;(fn=fnli.current());++fnli) // for each global function name |
|
7645 { |
|
7646 MemberNameIterator fni(*fn); |
|
7647 MemberDef *fmd; |
|
7648 for (;(fmd=fni.current());++fni) // for each function with that name |
|
7649 { |
|
7650 if (fmd->isTypedefValCached()) |
|
7651 { |
|
7652 ClassDef *cd = fmd->getCachedTypedefVal(); |
|
7653 if (cd->isTemplate()) fmd->invalidateTypedefValCache(); |
|
7654 } |
|
7655 } |
|
7656 } |
|
7657 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); |
|
7658 for (;(fn=mnli.current());++mnli) // for each class method name |
|
7659 { |
|
7660 MemberNameIterator mni(*fn); |
|
7661 MemberDef *fmd; |
|
7662 for (;(fmd=mni.current());++mni) // for each function with that name |
|
7663 { |
|
7664 if (fmd->isTypedefValCached()) |
|
7665 { |
|
7666 ClassDef *cd = fmd->getCachedTypedefVal(); |
|
7667 if (cd->isTemplate()) fmd->invalidateTypedefValCache(); |
|
7668 } |
|
7669 } |
|
7670 } |
|
7671 } |
|
7672 |
|
7673 //---------------------------------------------------------------------------- |
|
7674 |
|
7675 static void flushUnresolvedRelations() |
|
7676 { |
|
7677 // Remove all unresolved references to classes from the cache. |
|
7678 // This is needed before resolving the inheritance relations, since |
|
7679 // it would otherwise not find the inheritance relation |
|
7680 // for C in the example below, as B::I was already found to be unresolvable |
|
7681 // (which is correct if you igore the inheritance relation between A and B). |
|
7682 // |
|
7683 // class A { class I {} }; |
|
7684 // class B : public A {}; |
|
7685 // class C : public B::I {}; |
|
7686 // |
|
7687 QCacheIterator<LookupInfo> ci(Doxygen::lookupCache); |
|
7688 LookupInfo *li=0; |
|
7689 for (ci.toFirst();(li=ci.current());++ci) |
|
7690 { |
|
7691 if (li->classDef==0 && li->typeDef==0) |
|
7692 { |
|
7693 Doxygen::lookupCache.remove(ci.currentKey()); |
|
7694 } |
|
7695 } |
|
7696 |
|
7697 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); |
|
7698 MemberName *fn; |
|
7699 for (;(fn=fnli.current());++fnli) // for each global function name |
|
7700 { |
|
7701 MemberNameIterator fni(*fn); |
|
7702 MemberDef *fmd; |
|
7703 for (;(fmd=fni.current());++fni) // for each function with that name |
|
7704 { |
|
7705 fmd->invalidateCachedArgumentTypes(); |
|
7706 } |
|
7707 } |
|
7708 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); |
|
7709 for (;(fn=mnli.current());++mnli) // for each class method name |
|
7710 { |
|
7711 MemberNameIterator mni(*fn); |
|
7712 MemberDef *fmd; |
|
7713 for (;(fmd=mni.current());++mni) // for each function with that name |
|
7714 { |
|
7715 fmd->invalidateCachedArgumentTypes(); |
|
7716 } |
|
7717 } |
|
7718 |
|
7719 } |
|
7720 |
|
7721 //---------------------------------------------------------------------------- |
|
7722 |
|
7723 static void findDefineDocumentation(EntryNav *rootNav) |
|
7724 { |
|
7725 if ((rootNav->section()==Entry::DEFINEDOC_SEC || |
|
7726 rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty() |
|
7727 ) |
|
7728 { |
|
7729 rootNav->loadEntry(g_storage); |
|
7730 Entry *root = rootNav->entry(); |
|
7731 |
|
7732 //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n", |
|
7733 // root->name.data(),root->args.data(),root->brief.data(),root->doc.data()); |
|
7734 |
|
7735 if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file |
|
7736 { |
|
7737 MemberDef *md=new MemberDef("<tagfile>",1, |
|
7738 "#define",root->name,root->args,0, |
|
7739 Public,Normal,FALSE,Member,MemberDef::Define,0,0); |
|
7740 md->setTagInfo(rootNav->tagInfo()); |
|
7741 //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd); |
|
7742 md->setFileDef(rootNav->parent()->fileDef()); |
|
7743 //printf("Adding member=%s\n",md->name().data()); |
|
7744 MemberName *mn; |
|
7745 if ((mn=Doxygen::functionNameSDict->find(root->name))) |
|
7746 { |
|
7747 mn->append(md); |
|
7748 } |
|
7749 else |
|
7750 { |
|
7751 mn = new MemberName(root->name); |
|
7752 mn->append(md); |
|
7753 Doxygen::functionNameSDict->append(root->name,mn); |
|
7754 } |
|
7755 } |
|
7756 MemberName *mn=Doxygen::functionNameSDict->find(root->name); |
|
7757 if (mn) |
|
7758 { |
|
7759 int count=0; |
|
7760 MemberDef *md=mn->first(); |
|
7761 while (md) |
|
7762 { |
|
7763 if (md->memberType()==MemberDef::Define) count++; |
|
7764 md=mn->next(); |
|
7765 } |
|
7766 if (count==1) |
|
7767 { |
|
7768 md=mn->first(); |
|
7769 while (md) |
|
7770 { |
|
7771 if (md->memberType()==MemberDef::Define) |
|
7772 { |
|
7773 #if 0 |
|
7774 if (md->documentation().isEmpty()) |
|
7775 #endif |
|
7776 { |
|
7777 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
7778 md->setDocsForDefinition(!root->proto); |
|
7779 } |
|
7780 #if 0 |
|
7781 if (md->briefDescription().isEmpty()) |
|
7782 #endif |
|
7783 { |
|
7784 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
7785 } |
|
7786 if (md->inbodyDocumentation().isEmpty()) |
|
7787 { |
|
7788 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
7789 } |
|
7790 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
7791 md->setBodyDef(rootNav->fileDef()); |
|
7792 md->addSectionsToDefinition(root->anchors); |
|
7793 md->setMaxInitLines(root->initLines); |
|
7794 md->setRefItems(root->sli); |
|
7795 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId); |
|
7796 addMemberToGroups(root,md); |
|
7797 } |
|
7798 md=mn->next(); |
|
7799 } |
|
7800 } |
|
7801 else if (count>1 && |
|
7802 (!root->doc.isEmpty() || |
|
7803 !root->brief.isEmpty() || |
|
7804 root->bodyLine!=-1 |
|
7805 ) |
|
7806 ) |
|
7807 // multiple defines don't know where to add docs |
|
7808 // but maybe they are in different files together with their documentation |
|
7809 { |
|
7810 md=mn->first(); |
|
7811 while (md) |
|
7812 { |
|
7813 if (md->memberType()==MemberDef::Define) |
|
7814 { |
|
7815 FileDef *fd=md->getFileDef(); |
|
7816 if (fd && fd->absFilePath()==root->fileName) |
|
7817 // doc and define in the same file assume they belong together. |
|
7818 { |
|
7819 #if 0 |
|
7820 if (md->documentation().isEmpty()) |
|
7821 #endif |
|
7822 { |
|
7823 md->setDocumentation(root->doc,root->docFile,root->docLine); |
|
7824 md->setDocsForDefinition(!root->proto); |
|
7825 } |
|
7826 #if 0 |
|
7827 if (md->briefDescription().isEmpty()) |
|
7828 #endif |
|
7829 { |
|
7830 md->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
7831 } |
|
7832 if (md->inbodyDocumentation().isEmpty()) |
|
7833 { |
|
7834 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine); |
|
7835 } |
|
7836 md->setBodySegment(root->bodyLine,root->endBodyLine); |
|
7837 md->setBodyDef(rootNav->fileDef()); |
|
7838 md->addSectionsToDefinition(root->anchors); |
|
7839 md->setRefItems(root->sli); |
|
7840 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId); |
|
7841 addMemberToGroups(root,md); |
|
7842 } |
|
7843 } |
|
7844 md=mn->next(); |
|
7845 } |
|
7846 //warn("Warning: define %s found in the following files:\n",root->name.data()); |
|
7847 //warn("Cannot determine where to add the documentation found " |
|
7848 // "at line %d of file %s. \n", |
|
7849 // root->startLine,root->fileName.data()); |
|
7850 } |
|
7851 } |
|
7852 else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found |
|
7853 { |
|
7854 static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING"); |
|
7855 if (preEnabled) |
|
7856 { |
|
7857 warn(root->fileName,root->startLine, |
|
7858 "Warning: documentation for unknown define %s found.\n", |
|
7859 root->name.data() |
|
7860 ); |
|
7861 } |
|
7862 else |
|
7863 { |
|
7864 warn(root->fileName,root->startLine, |
|
7865 "Warning: found documented #define but ignoring it because " |
|
7866 "ENABLE_PREPROCESSING is NO.\n", |
|
7867 root->name.data() |
|
7868 ); |
|
7869 } |
|
7870 } |
|
7871 |
|
7872 rootNav->releaseEntry(); |
|
7873 } |
|
7874 RECURSE_ENTRYTREE(findDefineDocumentation,rootNav); |
|
7875 } |
|
7876 |
|
7877 //---------------------------------------------------------------------------- |
|
7878 |
|
7879 static void findDirDocumentation(EntryNav *rootNav) |
|
7880 { |
|
7881 if (rootNav->section() == Entry::DIRDOC_SEC) |
|
7882 { |
|
7883 rootNav->loadEntry(g_storage); |
|
7884 Entry *root = rootNav->entry(); |
|
7885 |
|
7886 QCString normalizedName = root->name; |
|
7887 normalizedName = substitute(normalizedName,"\\","/"); |
|
7888 if (normalizedName.at(normalizedName.length()-1)!='/') |
|
7889 { |
|
7890 normalizedName+='/'; |
|
7891 } |
|
7892 DirDef *dir,*matchingDir=0; |
|
7893 SDict<DirDef>::Iterator sdi(*Doxygen::directories); |
|
7894 for (sdi.toFirst();(dir=sdi.current());++sdi) |
|
7895 { |
|
7896 //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data()); |
|
7897 if (dir->name().right(normalizedName.length())==normalizedName) |
|
7898 { |
|
7899 if (matchingDir) |
|
7900 { |
|
7901 warn(root->fileName,root->startLine, |
|
7902 "Warning: \\dir command matches multiple directories.\n" |
|
7903 " Applying the command for directory %s\n" |
|
7904 " Ignoring the command for directory %s\n", |
|
7905 matchingDir->name().data(),dir->name().data() |
|
7906 ); |
|
7907 } |
|
7908 else |
|
7909 { |
|
7910 matchingDir=dir; |
|
7911 } |
|
7912 } |
|
7913 } |
|
7914 if (matchingDir) |
|
7915 { |
|
7916 //printf("Match for with dir %s\n",matchingDir->name().data()); |
|
7917 matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine); |
|
7918 matchingDir->setDocumentation(root->doc,root->docFile,root->docLine); |
|
7919 matchingDir->setRefItems(root->sli); |
|
7920 addDirToGroups(root,matchingDir); |
|
7921 } |
|
7922 else |
|
7923 { |
|
7924 warn(root->fileName,root->startLine,"Warning: No matching " |
|
7925 "directory found for command \\dir %s\n",root->name.data()); |
|
7926 } |
|
7927 rootNav->releaseEntry(); |
|
7928 } |
|
7929 RECURSE_ENTRYTREE(findDirDocumentation,rootNav); |
|
7930 } |
|
7931 |
|
7932 |
|
7933 //---------------------------------------------------------------------------- |
|
7934 // create a (sorted) list of separate documentation pages |
|
7935 |
|
7936 static void buildPageList(EntryNav *rootNav) |
|
7937 { |
|
7938 if (rootNav->section() == Entry::PAGEDOC_SEC) |
|
7939 { |
|
7940 rootNav->loadEntry(g_storage); |
|
7941 Entry *root = rootNav->entry(); |
|
7942 |
|
7943 if (!root->name.isEmpty()) |
|
7944 { |
|
7945 addRelatedPage(rootNav); |
|
7946 } |
|
7947 |
|
7948 rootNav->releaseEntry(); |
|
7949 } |
|
7950 else if (rootNav->section() == Entry::MAINPAGEDOC_SEC) |
|
7951 { |
|
7952 rootNav->loadEntry(g_storage); |
|
7953 Entry *root = rootNav->entry(); |
|
7954 |
|
7955 QCString title=root->args.stripWhiteSpace(); |
|
7956 if (title.isEmpty()) title=theTranslator->trMainPage(); |
|
7957 QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index"; |
|
7958 addRefItem(root->sli, |
|
7959 name, |
|
7960 "page", |
|
7961 name, |
|
7962 title, |
|
7963 0 |
|
7964 ); |
|
7965 |
|
7966 rootNav->releaseEntry(); |
|
7967 } |
|
7968 RECURSE_ENTRYTREE(buildPageList,rootNav); |
|
7969 } |
|
7970 |
|
7971 static void findMainPage(EntryNav *rootNav) |
|
7972 { |
|
7973 if (rootNav->section() == Entry::MAINPAGEDOC_SEC) |
|
7974 { |
|
7975 rootNav->loadEntry(g_storage); |
|
7976 Entry *root = rootNav->entry(); |
|
7977 |
|
7978 if (Doxygen::mainPage==0) |
|
7979 { |
|
7980 //printf("Found main page! \n======\n%s\n=======\n",root->doc.data()); |
|
7981 QCString title=root->args.stripWhiteSpace(); |
|
7982 QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index"; |
|
7983 Doxygen::mainPage = new PageDef(root->fileName,root->startLine, |
|
7984 indexName, root->brief+root->doc+root->inbodyDocs,title); |
|
7985 //setFileNameForSections(root->anchors,"index",Doxygen::mainPage); |
|
7986 Doxygen::mainPage->setFileName(indexName); |
|
7987 addPageToContext(Doxygen::mainPage,rootNav); |
|
7988 |
|
7989 // a page name is a label as well! |
|
7990 SectionInfo *si=new SectionInfo( |
|
7991 indexName, |
|
7992 Doxygen::mainPage->name(), |
|
7993 Doxygen::mainPage->title(), |
|
7994 SectionInfo::Page); |
|
7995 Doxygen::sectionDict.insert(indexName,si); |
|
7996 Doxygen::mainPage->addSectionsToDefinition(root->anchors); |
|
7997 } |
|
7998 else |
|
7999 { |
|
8000 warn(root->fileName,root->startLine, |
|
8001 "Warning: found more than one \\mainpage comment block! Skipping this " |
|
8002 "block." |
|
8003 ); |
|
8004 } |
|
8005 |
|
8006 rootNav->releaseEntry(); |
|
8007 } |
|
8008 RECURSE_ENTRYTREE(findMainPage,rootNav); |
|
8009 } |
|
8010 |
|
8011 static void computePageRelations(EntryNav *rootNav) |
|
8012 { |
|
8013 if ((rootNav->section()==Entry::PAGEDOC_SEC || |
|
8014 rootNav->section()==Entry::MAINPAGEDOC_SEC |
|
8015 ) |
|
8016 && !rootNav->name().isEmpty() |
|
8017 ) |
|
8018 { |
|
8019 rootNav->loadEntry(g_storage); |
|
8020 Entry *root = rootNav->entry(); |
|
8021 |
|
8022 PageDef *pd = root->section==Entry::PAGEDOC_SEC ? |
|
8023 Doxygen::pageSDict->find(root->name) : |
|
8024 Doxygen::mainPage; |
|
8025 if (pd) |
|
8026 { |
|
8027 QListIterator<BaseInfo> bii(*root->extends); |
|
8028 BaseInfo *bi; |
|
8029 for (bii.toFirst();(bi=bii.current());++bii) |
|
8030 { |
|
8031 PageDef *subPd = Doxygen::pageSDict->find(bi->name); |
|
8032 if (subPd) |
|
8033 { |
|
8034 pd->addInnerCompound(subPd); |
|
8035 //printf("*** Added subpage relation: %s->%s\n", |
|
8036 // pd->name().data(),subPd->name().data()); |
|
8037 } |
|
8038 } |
|
8039 } |
|
8040 |
|
8041 rootNav->releaseEntry(); |
|
8042 } |
|
8043 RECURSE_ENTRYTREE(computePageRelations,rootNav); |
|
8044 } |
|
8045 |
|
8046 static void checkPageRelations() |
|
8047 { |
|
8048 PageSDict::Iterator pdi(*Doxygen::pageSDict); |
|
8049 PageDef *pd=0; |
|
8050 for (pdi.toFirst();(pd=pdi.current());++pdi) |
|
8051 { |
|
8052 Definition *ppd = pd->getOuterScope(); |
|
8053 while (ppd) |
|
8054 { |
|
8055 if (ppd==pd) |
|
8056 { |
|
8057 err("Warning: page defined at line %d of file %s with label %s is a subpage " |
|
8058 "of itself! Please remove this cyclic dependency.\n", |
|
8059 pd->docLine(),pd->docFile().data(),pd->name().data()); |
|
8060 exit(1); |
|
8061 } |
|
8062 ppd=ppd->getOuterScope(); |
|
8063 } |
|
8064 } |
|
8065 } |
|
8066 |
|
8067 //---------------------------------------------------------------------------- |
|
8068 |
|
8069 static void resolveUserReferences() |
|
8070 { |
|
8071 QDictIterator<SectionInfo> sdi(Doxygen::sectionDict); |
|
8072 SectionInfo *si; |
|
8073 for (;(si=sdi.current());++sdi) |
|
8074 { |
|
8075 //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n", |
|
8076 // si->label.data(),si->definition?si->definition->name().data():"<none>", |
|
8077 // si->fileName.data()); |
|
8078 PageDef *pd=0; |
|
8079 |
|
8080 // hack: the items of a todo/test/bug/deprecated list are all fragments from |
|
8081 // different files, so the resulting section's all have the wrong file |
|
8082 // name (not from the todo/test/bug/deprecated list, but from the file in |
|
8083 // which they are defined). We correct this here by looking at the |
|
8084 // generated section labels! |
|
8085 QDictIterator<RefList> rli(*Doxygen::xrefLists); |
|
8086 RefList *rl; |
|
8087 for (rli.toFirst();(rl=rli.current());++rli) |
|
8088 { |
|
8089 QCString label="_"+rl->listName(); // "_todo", "_test", ... |
|
8090 if (si->label.left(label.length())==label) |
|
8091 { |
|
8092 si->fileName=rl->listName(); |
|
8093 si->generated=TRUE; |
|
8094 break; |
|
8095 } |
|
8096 } |
|
8097 |
|
8098 //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data()); |
|
8099 if (!si->generated) |
|
8100 { |
|
8101 // if this section is in a page and the page is in a group, then we |
|
8102 // have to adjust the link file name to point to the group. |
|
8103 if (!si->fileName.isEmpty() && |
|
8104 (pd=Doxygen::pageSDict->find(si->fileName)) && |
|
8105 pd->getGroupDef()) |
|
8106 { |
|
8107 si->fileName=pd->getGroupDef()->getOutputFileBase().copy(); |
|
8108 } |
|
8109 |
|
8110 if (si->definition) |
|
8111 { |
|
8112 // TODO: there should be one function in Definition that returns |
|
8113 // the file to link to, so we can avoid the following tests. |
|
8114 GroupDef *gd=0; |
|
8115 if (si->definition->definitionType()==Definition::TypeMember) |
|
8116 { |
|
8117 gd = ((MemberDef *)si->definition)->getGroupDef(); |
|
8118 } |
|
8119 |
|
8120 if (gd) |
|
8121 { |
|
8122 si->fileName=gd->getOutputFileBase().copy(); |
|
8123 } |
|
8124 else |
|
8125 { |
|
8126 //si->fileName=si->definition->getOutputFileBase().copy(); |
|
8127 //printf("Setting si->fileName to %s\n",si->fileName.data()); |
|
8128 } |
|
8129 } |
|
8130 } |
|
8131 //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data()); |
|
8132 } |
|
8133 } |
|
8134 |
|
8135 |
|
8136 //---------------------------------------------------------------------------- |
|
8137 // generate all separate documentation pages |
|
8138 |
|
8139 |
|
8140 static void generatePageDocs() |
|
8141 { |
|
8142 //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count()); |
|
8143 if (documentedPages==0) return; |
|
8144 PageSDict::Iterator pdi(*Doxygen::pageSDict); |
|
8145 PageDef *pd=0; |
|
8146 for (pdi.toFirst();(pd=pdi.current());++pdi) |
|
8147 { |
|
8148 if (!pd->getGroupDef() && !pd->isReference()) |
|
8149 { |
|
8150 msg("Generating docs for page %s...\n",pd->name().data()); |
|
8151 Doxygen::insideMainPage=TRUE; |
|
8152 pd->writeDocumentation(*g_outputList); |
|
8153 Doxygen::insideMainPage=FALSE; |
|
8154 } |
|
8155 } |
|
8156 } |
|
8157 |
|
8158 //---------------------------------------------------------------------------- |
|
8159 // create a (sorted) list & dictionary of example pages |
|
8160 |
|
8161 static void buildExampleList(EntryNav *rootNav) |
|
8162 { |
|
8163 if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) |
|
8164 { |
|
8165 rootNav->loadEntry(g_storage); |
|
8166 Entry *root = rootNav->entry(); |
|
8167 |
|
8168 if (Doxygen::exampleSDict->find(root->name)) |
|
8169 { |
|
8170 warn(root->fileName,root->startLine, |
|
8171 "Warning: Example %s was already documented. Ignoring " |
|
8172 "documentation found here.", |
|
8173 root->name.data() |
|
8174 ); |
|
8175 } |
|
8176 else |
|
8177 { |
|
8178 PageDef *pd=new PageDef(root->fileName,root->startLine, |
|
8179 root->name,root->brief+root->doc+root->inbodyDocs,root->args); |
|
8180 pd->setFileName(convertNameToFile(pd->name()+"-example")); |
|
8181 pd->addSectionsToDefinition(root->anchors); |
|
8182 //pi->addSections(root->anchors); |
|
8183 |
|
8184 Doxygen::exampleSDict->inSort(root->name,pd); |
|
8185 //we don't add example to groups |
|
8186 //addExampleToGroups(root,pd); |
|
8187 } |
|
8188 |
|
8189 rootNav->releaseEntry(); |
|
8190 } |
|
8191 RECURSE_ENTRYTREE(buildExampleList,rootNav); |
|
8192 } |
|
8193 |
|
8194 //---------------------------------------------------------------------------- |
|
8195 // prints the Entry tree (for debugging) |
|
8196 |
|
8197 void printNavTree(EntryNav *rootNav,int indent) |
|
8198 { |
|
8199 QCString indentStr; |
|
8200 indentStr.fill(' ',indent); |
|
8201 msg("%s%s (sec=0x%x)\n", |
|
8202 indentStr.isEmpty()?"":indentStr.data(), |
|
8203 rootNav->name().isEmpty()?"<empty>":rootNav->name().data(), |
|
8204 rootNav->section()); |
|
8205 if (rootNav->children()) |
|
8206 { |
|
8207 EntryNavListIterator eli(*rootNav->children()); |
|
8208 for (;eli.current();++eli) printNavTree(eli.current(),indent+2); |
|
8209 } |
|
8210 } |
|
8211 |
|
8212 |
|
8213 //---------------------------------------------------------------------------- |
|
8214 // generate the example documentation |
|
8215 |
|
8216 static void generateExampleDocs() |
|
8217 { |
|
8218 g_outputList->disable(OutputGenerator::Man); |
|
8219 PageSDict::Iterator pdi(*Doxygen::exampleSDict); |
|
8220 PageDef *pd=0; |
|
8221 for (pdi.toFirst();(pd=pdi.current());++pdi) |
|
8222 { |
|
8223 msg("Generating docs for example %s...\n",pd->name().data()); |
|
8224 resetCCodeParserState(); |
|
8225 QCString n=pd->getOutputFileBase(); |
|
8226 startFile(*g_outputList,n,n,pd->name()); |
|
8227 startTitle(*g_outputList,n); |
|
8228 g_outputList->docify(pd->name()); |
|
8229 endTitle(*g_outputList,n,0); |
|
8230 g_outputList->parseDoc(pd->docFile(), // file |
|
8231 pd->docLine(), // startLine |
|
8232 pd, // context |
|
8233 0, // memberDef |
|
8234 pd->documentation()+"\n\n\\include "+pd->name(), // docs |
|
8235 TRUE, // index words |
|
8236 TRUE, // is example |
|
8237 pd->name() |
|
8238 ); |
|
8239 endFile(*g_outputList); |
|
8240 } |
|
8241 g_outputList->enable(OutputGenerator::Man); |
|
8242 } |
|
8243 |
|
8244 //---------------------------------------------------------------------------- |
|
8245 // generate module pages |
|
8246 |
|
8247 static void generateGroupDocs() |
|
8248 { |
|
8249 GroupSDict::Iterator gli(*Doxygen::groupSDict); |
|
8250 GroupDef *gd; |
|
8251 for (gli.toFirst();(gd=gli.current());++gli) |
|
8252 { |
|
8253 if (!gd->isReference()) |
|
8254 { |
|
8255 gd->writeDocumentation(*g_outputList); |
|
8256 } |
|
8257 } |
|
8258 } |
|
8259 |
|
8260 //---------------------------------------------------------------------------- |
|
8261 |
|
8262 //static void generatePackageDocs() |
|
8263 //{ |
|
8264 // writePackageIndex(*g_outputList); |
|
8265 // |
|
8266 // if (Doxygen::packageDict.count()>0) |
|
8267 // { |
|
8268 // PackageSDict::Iterator pdi(Doxygen::packageDict); |
|
8269 // PackageDef *pd; |
|
8270 // for (pdi.toFirst();(pd=pdi.current());++pdi) |
|
8271 // { |
|
8272 // pd->writeDocumentation(*g_outputList); |
|
8273 // } |
|
8274 // } |
|
8275 //} |
|
8276 |
|
8277 //---------------------------------------------------------------------------- |
|
8278 // generate module pages |
|
8279 |
|
8280 static void generateNamespaceDocs() |
|
8281 { |
|
8282 writeNamespaceIndex(*g_outputList); |
|
8283 |
|
8284 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); |
|
8285 NamespaceDef *nd; |
|
8286 // for each namespace... |
|
8287 for (;(nd=nli.current());++nli) |
|
8288 { |
|
8289 |
|
8290 if (nd->isLinkableInProject()) |
|
8291 { |
|
8292 msg("Generating docs for namespace %s\n",nd->name().data()); |
|
8293 nd->writeDocumentation(*g_outputList); |
|
8294 } |
|
8295 |
|
8296 // for each class in the namespace... |
|
8297 ClassSDict::Iterator cli(*nd->getClassSDict()); |
|
8298 for ( ; cli.current() ; ++cli ) |
|
8299 { |
|
8300 ClassDef *cd=cli.current(); |
|
8301 if ( ( cd->isLinkableInProject() && |
|
8302 cd->templateMaster()==0 |
|
8303 ) // skip external references, anonymous compounds and |
|
8304 // template instances and nested classes |
|
8305 && !cd->isHidden() |
|
8306 ) |
|
8307 { |
|
8308 msg("Generating docs for compound %s...\n",cd->name().data()); |
|
8309 |
|
8310 cd->writeDocumentation(*g_outputList); |
|
8311 cd->writeMemberList(*g_outputList); |
|
8312 } |
|
8313 cd->writeDocumentationForInnerClasses(*g_outputList); |
|
8314 } |
|
8315 } |
|
8316 } |
|
8317 |
|
8318 #if defined(_WIN32) |
|
8319 static QCString fixSlashes(QCString &s) |
|
8320 { |
|
8321 QCString result; |
|
8322 uint i; |
|
8323 for (i=0;i<s.length();i++) |
|
8324 { |
|
8325 switch(s.at(i)) |
|
8326 { |
|
8327 case '/': |
|
8328 case '\\': |
|
8329 result+="\\\\"; |
|
8330 break; |
|
8331 default: |
|
8332 result+=s.at(i); |
|
8333 } |
|
8334 } |
|
8335 return result; |
|
8336 } |
|
8337 #endif |
|
8338 |
|
8339 |
|
8340 //---------------------------------------------------------------------------- |
|
8341 // generate files for the search engine |
|
8342 |
|
8343 //static void generateSearchIndex() |
|
8344 //{ |
|
8345 // if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTML")) |
|
8346 // { |
|
8347 // // create search index |
|
8348 // QCString fileName; |
|
8349 // writeSearchButton(Config_getString("HTML_OUTPUT")); |
|
8350 // |
|
8351 //#if !defined(_WIN32) |
|
8352 // // create cgi script |
|
8353 // fileName = Config_getString("HTML_OUTPUT")+"/"+Config_getString("CGI_NAME"); |
|
8354 // QFile f(fileName); |
|
8355 // if (f.open(IO_WriteOnly)) |
|
8356 // { |
|
8357 // QTextStream t(&f); |
|
8358 // t << "#!/bin/sh" << endl |
|
8359 // << "DOXYSEARCH=" << Config_getString("BIN_ABSPATH") << "/doxysearch" << endl |
|
8360 // << "DOXYPATH=\"" << Config_getString("DOC_ABSPATH") << " "; |
|
8361 // |
|
8362 // QStrList &extDocPaths=Config_getList("EXT_DOC_PATHS"); |
|
8363 // char *s= extDocPaths.first(); |
|
8364 // while (s) |
|
8365 // { |
|
8366 // t << s << " "; |
|
8367 // s=extDocPaths.next(); |
|
8368 // } |
|
8369 // |
|
8370 // t << "\"" << endl |
|
8371 // << "if [ -f $DOXYSEARCH ]" << endl |
|
8372 // << "then" << endl |
|
8373 // << " $DOXYSEARCH $DOXYPATH" << endl |
|
8374 // << "else" << endl |
|
8375 // << " echo \"Content-Type: text/html\"" << endl |
|
8376 // << " echo \"\"" << endl |
|
8377 // << " echo \"<h2>Error: $DOXYSEARCH not found. Check cgi script!</h2>\"" << endl |
|
8378 // << "fi" << endl; |
|
8379 // |
|
8380 // f.close(); |
|
8381 // struct stat stat_struct; |
|
8382 // stat(fileName,&stat_struct); |
|
8383 // chmod(fileName,stat_struct.st_mode|S_IXUSR|S_IXGRP|S_IXOTH); |
|
8384 // } |
|
8385 // else |
|
8386 // { |
|
8387 // err("Error: Cannot open file %s for writing\n",fileName.data()); |
|
8388 // } |
|
8389 //#else /* Windows platform */ |
|
8390 // // create cgi program |
|
8391 // fileName = Config_getString("CGI_NAME").copy(); |
|
8392 // if (fileName.right(4)==".cgi") |
|
8393 // fileName=fileName.left(fileName.length()-4); |
|
8394 // fileName+=".c"; |
|
8395 // fileName.prepend(Config_getString("HTML_OUTPUT")+"/"); |
|
8396 // QFile f(fileName); |
|
8397 // if (f.open(IO_WriteOnly)) |
|
8398 // { |
|
8399 // QTextStream t(&f); |
|
8400 // t << "#include <stdio.h>" << endl; |
|
8401 // t << "#include <stdlib.h>" << endl; |
|
8402 // t << "#include <process.h>" << endl; |
|
8403 // t << endl; |
|
8404 // t << "const char *DOXYSEARCH = \"" << |
|
8405 // fixSlashes(Config_getString("BIN_ABSPATH")) << "\\\\doxysearch.exe\";" << endl; |
|
8406 // t << "const char *DOXYPATH = \"" << |
|
8407 // fixSlashes(Config_getString("DOC_ABSPATH")) << "\";" << endl; |
|
8408 // t << endl; |
|
8409 // t << "int main(void)" << endl; |
|
8410 // t << "{" << endl; |
|
8411 // t << " char buf[1024];" << endl; |
|
8412 // t << " sprintf(buf,\"%s %s\",DOXYSEARCH,DOXYPATH);" << endl; |
|
8413 // t << " if (system(buf))" << endl; |
|
8414 // t << " {" << endl; |
|
8415 // t << " printf(\"Content-Type: text/html\\n\\n\");" << endl; |
|
8416 // t << " printf(\"<h2>Error: failed to execute %s</h2>\\n\",DOXYSEARCH);" << endl; |
|
8417 // t << " exit(1);" << endl; |
|
8418 // t << " }" << endl; |
|
8419 // t << " return 0;" << endl; |
|
8420 // t << "}" << endl; |
|
8421 // f.close(); |
|
8422 // } |
|
8423 // else |
|
8424 // { |
|
8425 // err("Error: Cannot open file %s for writing\n",fileName.data()); |
|
8426 // } |
|
8427 //#endif /* !defined(_WIN32) */ |
|
8428 // |
|
8429 // // create config file |
|
8430 // fileName = Config_getString("HTML_OUTPUT")+"/search.cfg"; |
|
8431 // f.setName(fileName); |
|
8432 // if (f.open(IO_WriteOnly)) |
|
8433 // { |
|
8434 // QTextStream t(&f); |
|
8435 // t << Config_getString("DOC_URL") << "/" << endl |
|
8436 // << Config_getString("CGI_URL") << "/" << Config_getString("CGI_NAME") << endl; |
|
8437 // f.close(); |
|
8438 // } |
|
8439 // else |
|
8440 // { |
|
8441 // err("Error: Cannot open file %s for writing\n",fileName.data()); |
|
8442 // } |
|
8443 // //g_outputList->generateExternalIndex(); |
|
8444 // g_outputList->pushGeneratorState(); |
|
8445 // g_outputList->disableAllBut(OutputGenerator::Html); |
|
8446 // startFile(*g_outputList,"header"+Doxygen::htmlFileExtension,0,"Search Engine",TRUE); |
|
8447 // g_outputList->endPlainFile(); |
|
8448 // g_outputList->startPlainFile("footer"+Doxygen::htmlFileExtension); |
|
8449 // endFile(*g_outputList,TRUE); |
|
8450 // g_outputList->popGeneratorState(); |
|
8451 // } |
|
8452 //} |
|
8453 |
|
8454 //---------------------------------------------------------------------------- |
|
8455 |
|
8456 static bool openOutputFile(const char *outFile,QFile &f) |
|
8457 { |
|
8458 bool fileOpened=FALSE; |
|
8459 bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0'); |
|
8460 if (writeToStdout) // write to stdout |
|
8461 { |
|
8462 fileOpened = f.open(IO_WriteOnly,stdout); |
|
8463 } |
|
8464 else // write to file |
|
8465 { |
|
8466 QFileInfo fi(outFile); |
|
8467 if (fi.exists()) // create a backup |
|
8468 { |
|
8469 QDir dir=fi.dir(); |
|
8470 QFileInfo backup(fi.fileName()+".bak"); |
|
8471 if (backup.exists()) // remove existing backup |
|
8472 dir.remove(backup.fileName()); |
|
8473 dir.rename(fi.fileName(),fi.fileName()+".bak"); |
|
8474 } |
|
8475 f.setName(outFile); |
|
8476 fileOpened = f.open(IO_WriteOnly|IO_Translate); |
|
8477 } |
|
8478 return fileOpened; |
|
8479 } |
|
8480 |
|
8481 /*! Generate a template version of the configuration file. |
|
8482 * If the \a shortList parameter is TRUE a configuration file without |
|
8483 * comments will be generated. |
|
8484 */ |
|
8485 static void generateConfigFile(const char *configFile,bool shortList, |
|
8486 bool updateOnly=FALSE) |
|
8487 { |
|
8488 QFile f; |
|
8489 bool fileOpened=openOutputFile(configFile,f); |
|
8490 bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0'); |
|
8491 if (fileOpened) |
|
8492 { |
|
8493 QTextStream t(&f); |
|
8494 t.setEncoding(QTextStream::UnicodeUTF8); |
|
8495 Config::instance()->writeTemplate(t,shortList,updateOnly); |
|
8496 if (!writeToStdout) |
|
8497 { |
|
8498 if (!updateOnly) |
|
8499 { |
|
8500 msg("\n\nConfiguration file `%s' created.\n\n",configFile); |
|
8501 msg("Now edit the configuration file and enter\n\n"); |
|
8502 if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile")) |
|
8503 msg(" doxygen %s\n\n",configFile); |
|
8504 else |
|
8505 msg(" doxygen\n\n"); |
|
8506 msg("to generate the documentation for your project\n\n"); |
|
8507 } |
|
8508 else |
|
8509 { |
|
8510 msg("\n\nConfiguration file `%s' updated.\n\n",configFile); |
|
8511 } |
|
8512 } |
|
8513 } |
|
8514 else |
|
8515 { |
|
8516 err("Error: Cannot open file %s for writing\n",configFile); |
|
8517 exit(1); |
|
8518 } |
|
8519 } |
|
8520 |
|
8521 //---------------------------------------------------------------------------- |
|
8522 // read and parse a tag file |
|
8523 |
|
8524 //static bool readLineFromFile(QFile &f,QCString &s) |
|
8525 //{ |
|
8526 // char c=0; |
|
8527 // s.resize(0); |
|
8528 // while (!f.atEnd() && (c=f.getch())!='\n') s+=c; |
|
8529 // return f.atEnd(); |
|
8530 //} |
|
8531 |
|
8532 //---------------------------------------------------------------------------- |
|
8533 |
|
8534 static void readTagFile(Entry *root,const char *tl) |
|
8535 { |
|
8536 QCString tagLine = tl; |
|
8537 QCString fileName; |
|
8538 QCString destName; |
|
8539 int eqPos = tagLine.find('='); |
|
8540 if (eqPos!=-1) // tag command contains a destination |
|
8541 { |
|
8542 fileName = tagLine.left(eqPos).stripWhiteSpace(); |
|
8543 destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace(); |
|
8544 QFileInfo fi(fileName); |
|
8545 Doxygen::tagDestinationDict.insert(fi.fileName(),new QCString(destName)); |
|
8546 //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data()); |
|
8547 } |
|
8548 else |
|
8549 { |
|
8550 fileName = tagLine; |
|
8551 } |
|
8552 |
|
8553 QFileInfo fi(fileName); |
|
8554 if (!fi.exists() || !fi.isFile()) |
|
8555 { |
|
8556 err("Error: Tag file `%s' does not exist or is not a file. Skipping it...\n", |
|
8557 fileName.data()); |
|
8558 return; |
|
8559 } |
|
8560 |
|
8561 if (!destName.isEmpty()) |
|
8562 msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data()); |
|
8563 else |
|
8564 msg("Reading tag file `%s'...\n",fileName.data()); |
|
8565 |
|
8566 parseTagFile(root,fi.absFilePath(),fi.fileName()); |
|
8567 |
|
8568 } |
|
8569 |
|
8570 //---------------------------------------------------------------------------- |
|
8571 // returns TRUE if the name of the file represented by `fi' matches |
|
8572 // one of the file patterns in the `patList' list. |
|
8573 |
|
8574 static bool patternMatch(QFileInfo *fi,QStrList *patList) |
|
8575 { |
|
8576 bool found=FALSE; |
|
8577 if (patList) |
|
8578 { |
|
8579 QCString pattern=patList->first(); |
|
8580 while (!pattern.isEmpty() && !found) |
|
8581 { |
|
8582 int i=pattern.find('='); |
|
8583 if (i!=-1) pattern=pattern.left(i); // strip of the extension specific filter name |
|
8584 |
|
8585 #if defined(_WIN32) // windows |
|
8586 QRegExp re(pattern,FALSE,TRUE); // case insensitive match |
|
8587 #else // unix |
|
8588 QRegExp re(pattern,TRUE,TRUE); // case sensitive match |
|
8589 #endif |
|
8590 found = found || re.match(fi->fileName())!=-1 || |
|
8591 re.match(fi->filePath())!=-1 || |
|
8592 re.match(fi->absFilePath())!=-1; |
|
8593 //printf("Matching `%s' against pattern `%s' found=%d\n", |
|
8594 // fi->fileName().data(),pattern.data(),found); |
|
8595 pattern=patList->next(); |
|
8596 } |
|
8597 } |
|
8598 return found; |
|
8599 } |
|
8600 |
|
8601 //---------------------------------------------------------------------------- |
|
8602 static void copyStyleSheet() |
|
8603 { |
|
8604 QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET"); |
|
8605 if (!htmlStyleSheet.isEmpty()) |
|
8606 { |
|
8607 QFile cssf(htmlStyleSheet); |
|
8608 QFileInfo cssfi(htmlStyleSheet); |
|
8609 if (cssf.open(IO_ReadOnly)) |
|
8610 { |
|
8611 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+cssfi.fileName().data(); |
|
8612 QFile df(destFileName); |
|
8613 if (df.open(IO_WriteOnly)) |
|
8614 { |
|
8615 char *buffer = new char[cssf.size()]; |
|
8616 cssf.readBlock(buffer,cssf.size()); |
|
8617 df.writeBlock(buffer,cssf.size()); |
|
8618 df.flush(); |
|
8619 delete[] buffer; |
|
8620 } |
|
8621 else |
|
8622 { |
|
8623 err("Error: could not write to style sheet %s\n",destFileName.data()); |
|
8624 } |
|
8625 } |
|
8626 else |
|
8627 { |
|
8628 err("Error: could not open user specified style sheet %s\n",Config_getString("HTML_STYLESHEET").data()); |
|
8629 htmlStyleSheet.resize(0); // revert to the default |
|
8630 } |
|
8631 } |
|
8632 } |
|
8633 |
|
8634 static void reportParseFileSize(const QCString *fileName, const BufStr &theBuf) |
|
8635 { |
|
8636 int numLines = 1; |
|
8637 int numWs = 0; |
|
8638 int byteCount = 0; |
|
8639 for (int i=0; i < theBuf.size(); ++i) { |
|
8640 if ('\n' == theBuf.at(i)) { |
|
8641 ++numLines; |
|
8642 } else if (' ' == theBuf.at(i)) { |
|
8643 ++numWs; |
|
8644 } |
|
8645 ++byteCount; |
|
8646 //if ('\0' == theBuf.at(i)) { |
|
8647 // break; |
|
8648 //} |
|
8649 } |
|
8650 msg("Have input for \"%s\", bytes=%d, buffer size=%d bytes, lines=%d ws=%d\n", |
|
8651 fileName->data(), |
|
8652 byteCount, |
|
8653 theBuf.size(), |
|
8654 numLines, |
|
8655 numWs); |
|
8656 } |
|
8657 |
|
8658 //! parse the list of input files |
|
8659 static void parseFiles(Entry *root,EntryNav *rootNav) |
|
8660 { |
|
8661 #if 0 |
|
8662 void *cd = 0; |
|
8663 QCString inpEncoding = Config_getString("INPUT_ENCODING"); |
|
8664 bool needsTranscoding = !inpEncoding.isEmpty(); |
|
8665 if (needsTranscoding) |
|
8666 { |
|
8667 if (!(cd = portable_iconv_open("UTF-8", inpEncoding))) |
|
8668 { |
|
8669 err("Error: unsupported character enconding: '%s'",inpEncoding.data()); |
|
8670 exit(1); |
|
8671 } |
|
8672 } |
|
8673 #endif |
|
8674 |
|
8675 QCString *s=g_inputFiles.first(); |
|
8676 while (s) |
|
8677 { |
|
8678 QCString fileName=*s; |
|
8679 QCString extension; |
|
8680 int ei = fileName.findRev('.'); |
|
8681 if (ei!=-1) extension=fileName.right(fileName.length()-ei); |
|
8682 ParserInterface *parser = Doxygen::parserManager->getParser(extension); |
|
8683 |
|
8684 QFileInfo fi(fileName); |
|
8685 BufStr preBuf(fi.size()+4096); |
|
8686 |
|
8687 if (Config_getBool("ENABLE_PREPROCESSING") && |
|
8688 parser->needsPreprocessing(extension)) |
|
8689 { |
|
8690 BufStr inBuf(fi.size()+4096); |
|
8691 msg("Preprocessing %s...\n",s->data()); |
|
8692 readInputFile(fileName,inBuf); |
|
8693 preprocessFile(fileName,inBuf,preBuf); |
|
8694 } |
|
8695 else // no preprocessing |
|
8696 { |
|
8697 msg("Reading %s...\n",s->data()); |
|
8698 readInputFile(fileName,preBuf); |
|
8699 } |
|
8700 reportParseFileSize(s, preBuf); |
|
8701 BufStr convBuf(preBuf.curPos()+1024); |
|
8702 |
|
8703 // convert multi-line C++ comments to C style comments |
|
8704 convertCppComments(&preBuf,&convBuf,fileName); |
|
8705 |
|
8706 convBuf.addChar('\0'); |
|
8707 |
|
8708 // use language parse to parse the file |
|
8709 parser->parseInput(fileName,convBuf.data(),root); |
|
8710 |
|
8711 // store the Entry tree in a file and create an index to |
|
8712 // navigate/load entries |
|
8713 bool ambig; |
|
8714 FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig); |
|
8715 ASSERT(fd!=0); |
|
8716 root->createNavigationIndex(rootNav,g_storage,fd); |
|
8717 |
|
8718 s=g_inputFiles.next(); |
|
8719 } |
|
8720 } |
|
8721 |
|
8722 // resolves a path that may include symlinks, if a recursive symlink is |
|
8723 // found an empty string is returned. |
|
8724 static QCString resolveSymlink(QCString path) |
|
8725 { |
|
8726 int sepPos=0; |
|
8727 QFileInfo fi; |
|
8728 QDict<void> nonSymlinks; |
|
8729 QDict<void> known; |
|
8730 QCString result = path; |
|
8731 QCString oldPrefix = "/"; |
|
8732 do |
|
8733 { |
|
8734 #ifdef WIN32 |
|
8735 // UNC path, skip server and share name |
|
8736 if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\")) |
|
8737 sepPos = result.find('/',2); |
|
8738 if (sepPos!=-1) |
|
8739 sepPos = result.find('/',sepPos+1); |
|
8740 #else |
|
8741 sepPos = result.find('/',sepPos+1); |
|
8742 #endif |
|
8743 QCString prefix = sepPos==-1 ? result : result.left(sepPos); |
|
8744 if (nonSymlinks.find(prefix)==0) |
|
8745 { |
|
8746 fi.setFile(prefix); |
|
8747 if (fi.isSymLink()) |
|
8748 { |
|
8749 QString target = fi.readLink(); |
|
8750 if (QFileInfo(target).isRelative()) |
|
8751 { |
|
8752 target = QDir::cleanDirPath(oldPrefix+"/"+target.data()); |
|
8753 } |
|
8754 if (sepPos!=-1) |
|
8755 { |
|
8756 if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/') |
|
8757 { |
|
8758 target+='/'; |
|
8759 } |
|
8760 target+=result.mid(sepPos); |
|
8761 } |
|
8762 result = QDir::cleanDirPath(target).data(); |
|
8763 sepPos = 0; |
|
8764 if (known.find(result)) return QCString(); // recursive symlink! |
|
8765 known.insert(result,(void*)0x8); |
|
8766 } |
|
8767 else |
|
8768 { |
|
8769 nonSymlinks.insert(prefix,(void*)0x8); |
|
8770 } |
|
8771 oldPrefix = prefix; |
|
8772 } |
|
8773 } |
|
8774 while (sepPos!=-1); |
|
8775 return QDir::cleanDirPath(result).data(); |
|
8776 } |
|
8777 |
|
8778 static QDict<void> g_pathsVisited(1009); |
|
8779 |
|
8780 //---------------------------------------------------------------------------- |
|
8781 // Read all files matching at least one pattern in `patList' in the |
|
8782 // directory represented by `fi'. |
|
8783 // The directory is read iff the recusiveFlag is set. |
|
8784 // The contents of all files is append to the input string |
|
8785 |
|
8786 int readDir(QFileInfo *fi, |
|
8787 FileNameList *fnList, |
|
8788 FileNameDict *fnDict, |
|
8789 StringDict *exclDict, |
|
8790 QStrList *patList, |
|
8791 QStrList *exclPatList, |
|
8792 StringList *resultList, |
|
8793 StringDict *resultDict, |
|
8794 bool errorIfNotExist, |
|
8795 bool recursive, |
|
8796 QDict<void> *killDict |
|
8797 ) |
|
8798 { |
|
8799 QString dirName = fi->absFilePath(); |
|
8800 if (fi->isSymLink()) |
|
8801 { |
|
8802 dirName = resolveSymlink(dirName.data()); |
|
8803 if (dirName.isEmpty()) return 0; // recusive symlink |
|
8804 if (g_pathsVisited.find(dirName)) return 0; // already visited path |
|
8805 g_pathsVisited.insert(dirName,(void*)0x8); |
|
8806 } |
|
8807 QDir dir(dirName); |
|
8808 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden ); |
|
8809 int totalSize=0; |
|
8810 msg("Searching for files in directory %s\n", fi->absFilePath().data()); |
|
8811 //printf("killDict=%p count=%d\n",killDict,killDict->count()); |
|
8812 |
|
8813 const QFileInfoList *list = dir.entryInfoList(); |
|
8814 if (list) |
|
8815 { |
|
8816 QFileInfoListIterator it( *list ); |
|
8817 QFileInfo *cfi; |
|
8818 |
|
8819 while ((cfi=it.current())) |
|
8820 { |
|
8821 if (exclDict==0 || exclDict->find(cfi->absFilePath())==0) |
|
8822 { // file should not be excluded |
|
8823 //printf("killDict->find(%s)\n",cfi->absFilePath().data()); |
|
8824 if (!cfi->exists() || !cfi->isReadable()) |
|
8825 { |
|
8826 if (errorIfNotExist) |
|
8827 { |
|
8828 err("Warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data()); |
|
8829 } |
|
8830 } |
|
8831 else if (cfi->isFile() && |
|
8832 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) && |
|
8833 (patList==0 || patternMatch(cfi,patList)) && |
|
8834 !patternMatch(cfi,exclPatList) && |
|
8835 (killDict==0 || killDict->find(cfi->absFilePath())==0) |
|
8836 ) |
|
8837 { |
|
8838 totalSize+=cfi->size()+cfi->absFilePath().length()+4; |
|
8839 QCString name=convertToQCString(cfi->fileName()); |
|
8840 //printf("New file %s\n",name.data()); |
|
8841 if (fnDict) |
|
8842 { |
|
8843 FileDef *fd=new FileDef(cfi->dirPath()+"/",name); |
|
8844 FileName *fn=0; |
|
8845 if (!name.isEmpty() && (fn=(*fnDict)[name])) |
|
8846 { |
|
8847 fn->append(fd); |
|
8848 } |
|
8849 else |
|
8850 { |
|
8851 fn = new FileName(cfi->absFilePath(),name); |
|
8852 fn->append(fd); |
|
8853 if (fnList) fnList->inSort(fn); |
|
8854 fnDict->insert(name,fn); |
|
8855 } |
|
8856 } |
|
8857 QCString *rs=0; |
|
8858 if (resultList || resultDict) |
|
8859 { |
|
8860 rs=new QCString(cfi->absFilePath()); |
|
8861 } |
|
8862 if (resultList) resultList->append(rs); |
|
8863 if (resultDict) resultDict->insert(cfi->absFilePath(),rs); |
|
8864 if (killDict) killDict->insert(cfi->absFilePath(),(void *)0x8); |
|
8865 } |
|
8866 else if (recursive && |
|
8867 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) && |
|
8868 cfi->isDir() && cfi->fileName()!="." && |
|
8869 !patternMatch(cfi,exclPatList) && |
|
8870 cfi->fileName()!="..") |
|
8871 { |
|
8872 cfi->setFile(cfi->absFilePath()); |
|
8873 totalSize+=readDir(cfi,fnList,fnDict,exclDict, |
|
8874 patList,exclPatList,resultList,resultDict,errorIfNotExist, |
|
8875 recursive,killDict); |
|
8876 } |
|
8877 } |
|
8878 ++it; |
|
8879 } |
|
8880 } |
|
8881 return totalSize; |
|
8882 } |
|
8883 |
|
8884 |
|
8885 //---------------------------------------------------------------------------- |
|
8886 // read a file or all files in a directory and append their contents to the |
|
8887 // input string. The names of the files are appended to the `fiList' list. |
|
8888 |
|
8889 int readFileOrDirectory(const char *s, |
|
8890 FileNameList *fnList, |
|
8891 FileNameDict *fnDict, |
|
8892 StringDict *exclDict, |
|
8893 QStrList *patList, |
|
8894 QStrList *exclPatList, |
|
8895 StringList *resultList, |
|
8896 StringDict *resultDict, |
|
8897 bool recursive, |
|
8898 bool errorIfNotExist, |
|
8899 QDict<void> *killDict |
|
8900 ) |
|
8901 { |
|
8902 //printf("killDict=%p count=%d\n",killDict,killDict->count()); |
|
8903 // strip trailing slashes |
|
8904 if (s==0) return 0; |
|
8905 QCString fs = s; |
|
8906 char lc = fs.at(fs.length()-1); |
|
8907 if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1); |
|
8908 |
|
8909 QFileInfo fi(fs); |
|
8910 //printf("readFileOrDirectory(%s)\n",s); |
|
8911 int totalSize=0; |
|
8912 { |
|
8913 if (exclDict==0 || exclDict->find(fi.absFilePath())==0) |
|
8914 { |
|
8915 if (!fi.exists() || !fi.isReadable()) |
|
8916 { |
|
8917 if (errorIfNotExist) |
|
8918 { |
|
8919 err("Warning: source %s is not a readable file or directory... skipping.\n",s); |
|
8920 } |
|
8921 } |
|
8922 else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink()) |
|
8923 { |
|
8924 if (fi.isFile()) |
|
8925 { |
|
8926 //printf("killDict->find(%s)\n",fi.absFilePath().data()); |
|
8927 if (killDict==0 || killDict->find(fi.absFilePath())==0) |
|
8928 { |
|
8929 totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); |
|
8930 //fiList->inSort(new FileInfo(fi)); |
|
8931 QCString name=convertToQCString(fi.fileName()); |
|
8932 //printf("New file %s\n",name.data()); |
|
8933 if (fnDict) |
|
8934 { |
|
8935 FileDef *fd=new FileDef(fi.dirPath(TRUE)+"/",name); |
|
8936 FileName *fn=0; |
|
8937 if (!name.isEmpty() && (fn=(*fnDict)[name])) |
|
8938 { |
|
8939 fn->append(fd); |
|
8940 } |
|
8941 else |
|
8942 { |
|
8943 fn = new FileName(fi.absFilePath(),name); |
|
8944 fn->append(fd); |
|
8945 if (fnList) fnList->inSort(fn); |
|
8946 fnDict->insert(name,fn); |
|
8947 } |
|
8948 } |
|
8949 QCString *rs=0; |
|
8950 if (resultList || resultDict) |
|
8951 { |
|
8952 rs=new QCString(fi.absFilePath()); |
|
8953 if (resultList) resultList->append(rs); |
|
8954 if (resultDict) resultDict->insert(fi.absFilePath(),rs); |
|
8955 } |
|
8956 |
|
8957 if (killDict) killDict->insert(fi.absFilePath(),(void *)0x8); |
|
8958 } |
|
8959 } |
|
8960 else if (fi.isDir()) // readable dir |
|
8961 { |
|
8962 totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList, |
|
8963 exclPatList,resultList,resultDict,errorIfNotExist, |
|
8964 recursive,killDict); |
|
8965 } |
|
8966 } |
|
8967 } |
|
8968 } |
|
8969 return totalSize; |
|
8970 } |
|
8971 |
|
8972 //---------------------------------------------------------------------------- |
|
8973 |
|
8974 void readFormulaRepository() |
|
8975 { |
|
8976 QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository"); |
|
8977 if (f.open(IO_ReadOnly)) // open repository |
|
8978 { |
|
8979 msg("Reading formula repository...\n"); |
|
8980 QTextStream t(&f); |
|
8981 QCString line; |
|
8982 while (!t.eof()) |
|
8983 { |
|
8984 line=t.readLine(); |
|
8985 int se=line.find(':'); // find name and text separator. |
|
8986 if (se==-1) |
|
8987 { |
|
8988 err("Warning: formula.repository is corrupted!\n"); |
|
8989 break; |
|
8990 } |
|
8991 else |
|
8992 { |
|
8993 QCString formName = line.left(se); |
|
8994 QCString formText = line.right(line.length()-se-1); |
|
8995 Formula *f=new Formula(formText); |
|
8996 Doxygen::formulaList.append(f); |
|
8997 Doxygen::formulaDict.insert(formText,f); |
|
8998 Doxygen::formulaNameDict.insert(formName,f); |
|
8999 } |
|
9000 } |
|
9001 } |
|
9002 } |
|
9003 |
|
9004 //---------------------------------------------------------------------------- |
|
9005 |
|
9006 static void expandAliases() |
|
9007 { |
|
9008 QDictIterator<QCString> adi(Doxygen::aliasDict); |
|
9009 QCString *s; |
|
9010 for (adi.toFirst();(s=adi.current());++adi) |
|
9011 { |
|
9012 *s = expandAlias(adi.currentKey(),*s); |
|
9013 } |
|
9014 } |
|
9015 |
|
9016 //---------------------------------------------------------------------------- |
|
9017 |
|
9018 static void escapeAliases() |
|
9019 { |
|
9020 QDictIterator<QCString> adi(Doxygen::aliasDict); |
|
9021 QCString *s; |
|
9022 for (adi.toFirst();(s=adi.current());++adi) |
|
9023 { |
|
9024 QCString value=*s,newValue; |
|
9025 int in,p=0; |
|
9026 // for each \n in the alias command value |
|
9027 while ((in=value.find("\\n",p))!=-1) |
|
9028 { |
|
9029 newValue+=value.mid(p,in-p); |
|
9030 // expand \n's except if \n is part of a built-in command. |
|
9031 if (value.mid(in,5)!="\\note" && |
|
9032 value.mid(in,5)!="\\name" && |
|
9033 value.mid(in,10)!="\\namespace" && |
|
9034 value.mid(in,14)!="\\nosubgrouping" |
|
9035 ) |
|
9036 { |
|
9037 newValue+="\\_linebr "; |
|
9038 } |
|
9039 else |
|
9040 { |
|
9041 newValue+="\\n"; |
|
9042 } |
|
9043 p=in+2; |
|
9044 } |
|
9045 newValue+=value.mid(p,value.length()-p); |
|
9046 *s=newValue; |
|
9047 //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data()); |
|
9048 } |
|
9049 } |
|
9050 |
|
9051 //---------------------------------------------------------------------------- |
|
9052 |
|
9053 void readAliases() |
|
9054 { |
|
9055 // add aliases to a dictionary |
|
9056 Doxygen::aliasDict.setAutoDelete(TRUE); |
|
9057 QStrList &aliasList = Config_getList("ALIASES"); |
|
9058 const char *s=aliasList.first(); |
|
9059 while (s) |
|
9060 { |
|
9061 if (Doxygen::aliasDict[s]==0) |
|
9062 { |
|
9063 QCString alias=s; |
|
9064 int i=alias.find('='); |
|
9065 if (i>0) |
|
9066 { |
|
9067 QCString name=alias.left(i).stripWhiteSpace(); |
|
9068 QCString value=alias.right(alias.length()-i-1); |
|
9069 //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); |
|
9070 if (!name.isEmpty()) |
|
9071 { |
|
9072 QCString *dn=Doxygen::aliasDict[name]; |
|
9073 if (dn==0) // insert new alias |
|
9074 { |
|
9075 Doxygen::aliasDict.insert(name,new QCString(value)); |
|
9076 } |
|
9077 else // overwrite previous alias |
|
9078 { |
|
9079 *dn=value; |
|
9080 } |
|
9081 } |
|
9082 } |
|
9083 } |
|
9084 s=aliasList.next(); |
|
9085 } |
|
9086 expandAliases(); |
|
9087 escapeAliases(); |
|
9088 } |
|
9089 |
|
9090 //---------------------------------------------------------------------------- |
|
9091 |
|
9092 static void dumpSymbol(QTextStream &t,Definition *d) |
|
9093 { |
|
9094 QCString anchor; |
|
9095 if (d->definitionType()==Definition::TypeMember) |
|
9096 { |
|
9097 MemberDef *md = (MemberDef *)d; |
|
9098 anchor=":"+md->anchor(); |
|
9099 } |
|
9100 QCString scope; |
|
9101 if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) |
|
9102 { |
|
9103 scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension; |
|
9104 } |
|
9105 t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('" |
|
9106 << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','" |
|
9107 << scope << "','" |
|
9108 << d->name() << "','" |
|
9109 << d->getDefFileName() << "','" |
|
9110 << d->getDefLine() |
|
9111 << "');" << endl; |
|
9112 } |
|
9113 |
|
9114 static void dumpSymbolMap() |
|
9115 { |
|
9116 QFile f("symbols.sql"); |
|
9117 if (f.open(IO_WriteOnly)) |
|
9118 { |
|
9119 QTextStream t(&f); |
|
9120 QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap); |
|
9121 DefinitionIntf *intf; |
|
9122 for (;(intf=di.current());++di) |
|
9123 { |
|
9124 if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols |
|
9125 { |
|
9126 DefinitionListIterator dli(*(DefinitionList*)intf); |
|
9127 Definition *d; |
|
9128 // for each symbol |
|
9129 for (dli.toFirst();(d=dli.current());++dli) |
|
9130 { |
|
9131 dumpSymbol(t,d); |
|
9132 } |
|
9133 } |
|
9134 else // single symbol |
|
9135 { |
|
9136 Definition *d = (Definition *)intf; |
|
9137 if (d!=Doxygen::globalScope) dumpSymbol(t,d); |
|
9138 } |
|
9139 } |
|
9140 } |
|
9141 } |
|
9142 |
|
9143 //---------------------------------------------------------------------------- |
|
9144 |
|
9145 void dumpConfigAsXML() |
|
9146 { |
|
9147 QFile f("config.xml"); |
|
9148 if (f.open(IO_WriteOnly)) |
|
9149 { |
|
9150 QTextStream t(&f); |
|
9151 Config::instance()->writeXML(t); |
|
9152 } |
|
9153 } |
|
9154 |
|
9155 //---------------------------------------------------------------------------- |
|
9156 // print the usage of doxygen |
|
9157 |
|
9158 static void usage(const char *name) |
|
9159 { |
|
9160 msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2008\n\n",versionString); |
|
9161 msg("You can use doxygen in a number of ways:\n\n"); |
|
9162 msg("1) Use doxygen to generate a template configuration file:\n"); |
|
9163 msg(" %s [-s] -g [configName]\n\n",name); |
|
9164 msg(" If - is used for configName doxygen will write to standard output.\n\n"); |
|
9165 msg("2) Use doxygen to update an old configuration file:\n"); |
|
9166 msg(" %s [-s] -u [configName]\n\n",name); |
|
9167 msg("3) Use doxygen to generate documentation using an existing "); |
|
9168 msg("configuration file:\n"); |
|
9169 msg(" %s [configName]\n\n",name); |
|
9170 msg(" If - is used for configName doxygen will read from standard input.\n\n"); |
|
9171 msg("4) Use doxygen to generate a template file controlling the layout of the\n"); |
|
9172 msg(" generated documentation:\n"); |
|
9173 msg(" %s -l layoutFileName.xml\n\n",name); |
|
9174 msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n"); |
|
9175 msg(" RTF: %s -w rtf styleSheetFile\n",name); |
|
9176 msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name); |
|
9177 msg(" LaTeX: %s -w latex headerFile styleSheetFile [configFile]\n\n",name); |
|
9178 msg("6) Use doxygen to generate an rtf extensions file\n"); |
|
9179 msg(" RTF: %s -e rtf extensionsFile\n\n",name); |
|
9180 msg("If -s is specified the comments in the config file will be omitted.\n"); |
|
9181 msg("If configName is omitted `Doxyfile' will be used as a default.\n\n"); |
|
9182 exit(1); |
|
9183 } |
|
9184 |
|
9185 //---------------------------------------------------------------------------- |
|
9186 // read the argument of option `c' from the comment argument list and |
|
9187 // update the option index `optind'. |
|
9188 |
|
9189 static const char *getArg(int argc,char **argv,int &optind) |
|
9190 { |
|
9191 char *s=0; |
|
9192 if (strlen(&argv[optind][2])>0) |
|
9193 s=&argv[optind][2]; |
|
9194 else if (optind+1<argc && argv[optind+1][0]!='-') |
|
9195 s=argv[++optind]; |
|
9196 return s; |
|
9197 } |
|
9198 |
|
9199 //---------------------------------------------------------------------------- |
|
9200 |
|
9201 extern void commentScanTest(); |
|
9202 |
|
9203 void initDoxygen() |
|
9204 { |
|
9205 setlocale(LC_ALL,""); |
|
9206 setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8 |
|
9207 setlocale(LC_NUMERIC,"C"); |
|
9208 |
|
9209 //Doxygen::symbolMap->setAutoDelete(TRUE); |
|
9210 |
|
9211 Doxygen::runningTime.start(); |
|
9212 initPreprocessor(); |
|
9213 |
|
9214 Doxygen::parserManager = new ParserManager; |
|
9215 Doxygen::parserManager->registerParser("c", new CLanguageScanner, TRUE); |
|
9216 Doxygen::parserManager->registerParser("python", new PythonLanguageScanner); |
|
9217 Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner); |
|
9218 Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner); |
|
9219 Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner); |
|
9220 |
|
9221 // register any additional parsers here... |
|
9222 |
|
9223 initDefaultExtensionMapping(); |
|
9224 initClassMemberIndices(); |
|
9225 initNamespaceMemberIndices(); |
|
9226 initFileMemberIndices(); |
|
9227 |
|
9228 Doxygen::symbolMap = new QDict<DefinitionIntf>(1000); |
|
9229 Doxygen::inputNameList = new FileNameList; |
|
9230 Doxygen::inputNameList->setAutoDelete(TRUE); |
|
9231 Doxygen::memberNameSDict = new MemberNameSDict(10000); |
|
9232 Doxygen::memberNameSDict->setAutoDelete(TRUE); |
|
9233 Doxygen::functionNameSDict = new MemberNameSDict(10000); |
|
9234 Doxygen::functionNameSDict->setAutoDelete(TRUE); |
|
9235 Doxygen::groupSDict = new GroupSDict(17); |
|
9236 Doxygen::groupSDict->setAutoDelete(TRUE); |
|
9237 Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>"); |
|
9238 Doxygen::namespaceSDict = new NamespaceSDict(20); |
|
9239 Doxygen::namespaceSDict->setAutoDelete(TRUE); |
|
9240 Doxygen::classSDict = new ClassSDict(1009); |
|
9241 Doxygen::classSDict->setAutoDelete(TRUE); |
|
9242 Doxygen::hiddenClasses = new ClassSDict(257); |
|
9243 Doxygen::hiddenClasses->setAutoDelete(TRUE); |
|
9244 Doxygen::directories = new DirSDict(17); |
|
9245 Doxygen::directories->setAutoDelete(TRUE); |
|
9246 Doxygen::pageSDict = new PageSDict(1009); // all doc pages |
|
9247 Doxygen::pageSDict->setAutoDelete(TRUE); |
|
9248 Doxygen::exampleSDict = new PageSDict(1009); // all examples |
|
9249 Doxygen::exampleSDict->setAutoDelete(TRUE); |
|
9250 Doxygen::inputNameDict = new FileNameDict(10007); |
|
9251 Doxygen::includeNameDict = new FileNameDict(10007); |
|
9252 Doxygen::exampleNameDict = new FileNameDict(1009); |
|
9253 Doxygen::exampleNameDict->setAutoDelete(TRUE); |
|
9254 Doxygen::imageNameDict = new FileNameDict(257); |
|
9255 Doxygen::dotFileNameDict = new FileNameDict(257); |
|
9256 Doxygen::sectionDict.setAutoDelete(TRUE); |
|
9257 Doxygen::memGrpInfoDict.setAutoDelete(TRUE); |
|
9258 Doxygen::tagDestinationDict.setAutoDelete(TRUE); |
|
9259 Doxygen::lookupCache.setAutoDelete(TRUE); |
|
9260 Doxygen::dirRelations.setAutoDelete(TRUE); |
|
9261 } |
|
9262 |
|
9263 void cleanUpDoxygen() |
|
9264 { |
|
9265 delete Doxygen::inputNameDict; |
|
9266 delete Doxygen::includeNameDict; |
|
9267 delete Doxygen::exampleNameDict; |
|
9268 delete Doxygen::imageNameDict; |
|
9269 delete Doxygen::dotFileNameDict; |
|
9270 delete Doxygen::mainPage; |
|
9271 delete Doxygen::pageSDict; |
|
9272 delete Doxygen::exampleSDict; |
|
9273 delete Doxygen::globalScope; |
|
9274 delete Doxygen::xrefLists; |
|
9275 delete Doxygen::parserManager; |
|
9276 cleanUpPreprocessor(); |
|
9277 delete theTranslator; |
|
9278 delete g_outputList; |
|
9279 Mappers::freeMappers(); |
|
9280 codeFreeScanner(); |
|
9281 |
|
9282 if (Doxygen::symbolMap) |
|
9283 { |
|
9284 // iterate through Doxygen::symbolMap and delete all |
|
9285 // DefinitionList objects, since they have no owner |
|
9286 QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap); |
|
9287 DefinitionIntf *di; |
|
9288 for (dli.toFirst();(di=dli.current());) |
|
9289 { |
|
9290 if (di->definitionType()==DefinitionIntf::TypeSymbolList) |
|
9291 { |
|
9292 DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey()); |
|
9293 delete (DefinitionList *)tmp; |
|
9294 } |
|
9295 else |
|
9296 { |
|
9297 ++dli; |
|
9298 } |
|
9299 } |
|
9300 } |
|
9301 |
|
9302 delete Doxygen::inputNameList; |
|
9303 delete Doxygen::memberNameSDict; |
|
9304 delete Doxygen::functionNameSDict; |
|
9305 delete Doxygen::groupSDict; |
|
9306 delete Doxygen::classSDict; |
|
9307 delete Doxygen::hiddenClasses; |
|
9308 delete Doxygen::namespaceSDict; |
|
9309 delete Doxygen::directories; |
|
9310 |
|
9311 //delete Doxygen::symbolMap; <- we cannot do this unless all static lists |
|
9312 // (such as Doxygen::namespaceSDict) |
|
9313 // with objects based on Definition are made |
|
9314 // dynamic first |
|
9315 } |
|
9316 |
|
9317 void readConfiguration(int argc, char **argv) |
|
9318 { |
|
9319 /************************************************************************** |
|
9320 * Handle arguments * |
|
9321 **************************************************************************/ |
|
9322 |
|
9323 int optind=1; |
|
9324 const char *configName=0; |
|
9325 const char *layoutName=0; |
|
9326 const char *debugLabel; |
|
9327 const char *formatName; |
|
9328 bool genConfig=FALSE; |
|
9329 bool shortList=FALSE; |
|
9330 bool updateConfig=FALSE; |
|
9331 bool genLayout=FALSE; |
|
9332 while (optind<argc && argv[optind][0]=='-' && |
|
9333 (isalpha(argv[optind][1]) || argv[optind][1]=='?' || |
|
9334 argv[optind][1]=='-') |
|
9335 ) |
|
9336 { |
|
9337 switch(argv[optind][1]) |
|
9338 { |
|
9339 case 'g': |
|
9340 genConfig=TRUE; |
|
9341 configName=getArg(argc,argv,optind); |
|
9342 if (strcmp(argv[optind+1],"-")==0) |
|
9343 { configName="-"; optind++; } |
|
9344 if (!configName) |
|
9345 { configName="Doxyfile"; } |
|
9346 break; |
|
9347 case 'l': |
|
9348 genLayout=TRUE; |
|
9349 layoutName=getArg(argc,argv,optind); |
|
9350 if (!layoutName) |
|
9351 { layoutName="DoxygenLayout.xml"; } |
|
9352 break; |
|
9353 case 'd': |
|
9354 debugLabel=getArg(argc,argv,optind); |
|
9355 Debug::setFlag(debugLabel); |
|
9356 break; |
|
9357 case 's': |
|
9358 shortList=TRUE; |
|
9359 break; |
|
9360 case 'u': |
|
9361 updateConfig=TRUE; |
|
9362 break; |
|
9363 case 'e': |
|
9364 formatName=getArg(argc,argv,optind); |
|
9365 if (!formatName) |
|
9366 { |
|
9367 err("Error:option -e is missing format specifier rtf.\n"); |
|
9368 cleanUpDoxygen(); |
|
9369 exit(1); |
|
9370 } |
|
9371 if (stricmp(formatName,"rtf")==0) |
|
9372 { |
|
9373 if (optind+1>=argc) |
|
9374 { |
|
9375 err("Error: option \"-e rtf\" is missing an extensions file name\n"); |
|
9376 cleanUpDoxygen(); |
|
9377 exit(1); |
|
9378 } |
|
9379 QFile f; |
|
9380 if (openOutputFile(argv[optind+1],f)) |
|
9381 { |
|
9382 RTFGenerator::writeExtensionsFile(f); |
|
9383 } |
|
9384 cleanUpDoxygen(); |
|
9385 exit(1); |
|
9386 } |
|
9387 err("Error: option \"-e\" has invalid format specifier.\n"); |
|
9388 cleanUpDoxygen(); |
|
9389 exit(1); |
|
9390 break; |
|
9391 case 'w': |
|
9392 formatName=getArg(argc,argv,optind); |
|
9393 if (!formatName) |
|
9394 { |
|
9395 err("Error: option -w is missing format specifier rtf, html or latex\n"); |
|
9396 cleanUpDoxygen(); |
|
9397 exit(1); |
|
9398 } |
|
9399 if (stricmp(formatName,"rtf")==0) |
|
9400 { |
|
9401 if (optind+1>=argc) |
|
9402 { |
|
9403 err("Error: option \"-w rtf\" is missing a style sheet file name\n"); |
|
9404 cleanUpDoxygen(); |
|
9405 exit(1); |
|
9406 } |
|
9407 QFile f; |
|
9408 if (openOutputFile(argv[optind+1],f)) |
|
9409 { |
|
9410 RTFGenerator::writeStyleSheetFile(f); |
|
9411 } |
|
9412 cleanUpDoxygen(); |
|
9413 exit(1); |
|
9414 } |
|
9415 else if (stricmp(formatName,"html")==0) |
|
9416 { |
|
9417 if (optind+4<argc) |
|
9418 { |
|
9419 if (!Config::instance()->parse(argv[optind+4])) |
|
9420 { |
|
9421 err("Error opening or reading configuration file %s!\n",argv[optind+4]); |
|
9422 cleanUpDoxygen(); |
|
9423 exit(1); |
|
9424 } |
|
9425 Config::instance()->substituteEnvironmentVars(); |
|
9426 Config::instance()->convertStrToVal(); |
|
9427 Config::instance()->check(); |
|
9428 } |
|
9429 else |
|
9430 { |
|
9431 Config::instance()->init(); |
|
9432 } |
|
9433 if (optind+3>=argc) |
|
9434 { |
|
9435 err("Error: option \"-w html\" does not have enough arguments\n"); |
|
9436 cleanUpDoxygen(); |
|
9437 exit(1); |
|
9438 } |
|
9439 |
|
9440 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); |
|
9441 if (!setTranslator(outputLanguage)) |
|
9442 { |
|
9443 err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data()); |
|
9444 } |
|
9445 |
|
9446 QFile f; |
|
9447 if (openOutputFile(argv[optind+1],f)) |
|
9448 { |
|
9449 HtmlGenerator::writeHeaderFile(f); |
|
9450 } |
|
9451 f.close(); |
|
9452 if (openOutputFile(argv[optind+2],f)) |
|
9453 { |
|
9454 HtmlGenerator::writeFooterFile(f); |
|
9455 } |
|
9456 f.close(); |
|
9457 if (openOutputFile(argv[optind+3],f)) |
|
9458 { |
|
9459 HtmlGenerator::writeStyleSheetFile(f); |
|
9460 } |
|
9461 cleanUpDoxygen(); |
|
9462 exit(0); |
|
9463 } |
|
9464 else if (stricmp(formatName,"latex")==0) |
|
9465 { |
|
9466 if (optind+3<argc) // use config file to get settings |
|
9467 { |
|
9468 if (!Config::instance()->parse(argv[optind+3])) |
|
9469 { |
|
9470 err("Error opening or reading configuration file %s!\n",argv[optind+3]); |
|
9471 exit(1); |
|
9472 } |
|
9473 Config::instance()->substituteEnvironmentVars(); |
|
9474 Config::instance()->convertStrToVal(); |
|
9475 Config::instance()->check(); |
|
9476 } |
|
9477 else // use default config |
|
9478 { |
|
9479 Config::instance()->init(); |
|
9480 } |
|
9481 if (optind+2>=argc) |
|
9482 { |
|
9483 err("Error: option \"-w latex\" does not have enough arguments\n"); |
|
9484 cleanUpDoxygen(); |
|
9485 exit(1); |
|
9486 } |
|
9487 |
|
9488 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); |
|
9489 if (!setTranslator(outputLanguage)) |
|
9490 { |
|
9491 err("Warning: Output language %s not supported! Using English instead.\n", outputLanguage.data()); |
|
9492 } |
|
9493 |
|
9494 QFile f; |
|
9495 if (openOutputFile(argv[optind+1],f)) |
|
9496 { |
|
9497 LatexGenerator::writeHeaderFile(f); |
|
9498 } |
|
9499 f.close(); |
|
9500 if (openOutputFile(argv[optind+2],f)) |
|
9501 { |
|
9502 LatexGenerator::writeStyleSheetFile(f); |
|
9503 } |
|
9504 cleanUpDoxygen(); |
|
9505 exit(0); |
|
9506 } |
|
9507 else |
|
9508 { |
|
9509 err("Error: Illegal format specifier %s: should be one of rtf, html, or latex\n",formatName); |
|
9510 cleanUpDoxygen(); |
|
9511 exit(1); |
|
9512 } |
|
9513 break; |
|
9514 case 'm': |
|
9515 g_dumpSymbolMap = TRUE; |
|
9516 break; |
|
9517 case 'x': |
|
9518 g_dumpConfigAsXML = TRUE; |
|
9519 break; |
|
9520 case '-': |
|
9521 if (strcmp(&argv[optind][2],"help")==0) |
|
9522 { |
|
9523 usage(argv[0]); |
|
9524 } |
|
9525 else if (strcmp(&argv[optind][2],"version")==0) |
|
9526 { |
|
9527 msg("%s\n",versionString); |
|
9528 cleanUpDoxygen(); |
|
9529 exit(0); |
|
9530 } |
|
9531 break; |
|
9532 case 'b': |
|
9533 setvbuf(stdout,NULL,_IONBF,0); |
|
9534 Doxygen::outputToWizard=TRUE; |
|
9535 break; |
|
9536 case 'h': |
|
9537 case '?': |
|
9538 usage(argv[0]); |
|
9539 break; |
|
9540 default: |
|
9541 err("Unknown option -%c\n",argv[optind][1]); |
|
9542 usage(argv[0]); |
|
9543 } |
|
9544 optind++; |
|
9545 } |
|
9546 |
|
9547 /************************************************************************** |
|
9548 * Parse or generate the config file * |
|
9549 **************************************************************************/ |
|
9550 |
|
9551 Config::instance()->init(); |
|
9552 |
|
9553 if (genConfig) |
|
9554 { |
|
9555 if (g_dumpConfigAsXML) |
|
9556 { |
|
9557 checkConfiguration(); |
|
9558 generateConfigFile(configName,shortList); |
|
9559 dumpConfigAsXML(); |
|
9560 exit(0); |
|
9561 } |
|
9562 else |
|
9563 { |
|
9564 generateConfigFile(configName,shortList); |
|
9565 } |
|
9566 cleanUpDoxygen(); |
|
9567 exit(0); |
|
9568 } |
|
9569 if (genLayout) |
|
9570 { |
|
9571 writeDefaultLayoutFile(layoutName); |
|
9572 cleanUpDoxygen(); |
|
9573 exit(0); |
|
9574 } |
|
9575 |
|
9576 QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile"); |
|
9577 if (optind>=argc) |
|
9578 { |
|
9579 if (configFileInfo1.exists()) |
|
9580 { |
|
9581 configName="Doxyfile"; |
|
9582 } |
|
9583 else if (configFileInfo2.exists()) |
|
9584 { |
|
9585 configName="doxyfile"; |
|
9586 } |
|
9587 else |
|
9588 { |
|
9589 err("Doxyfile not found and no input file specified!\n"); |
|
9590 usage(argv[0]); |
|
9591 } |
|
9592 } |
|
9593 else |
|
9594 { |
|
9595 QFileInfo fi(argv[optind]); |
|
9596 if (fi.exists() || strcmp(argv[optind],"-")==0) |
|
9597 { |
|
9598 configName=argv[optind]; |
|
9599 } |
|
9600 else |
|
9601 { |
|
9602 err("Error: configuration file %s not found!\n",argv[optind]); |
|
9603 usage(argv[0]); |
|
9604 } |
|
9605 } |
|
9606 |
|
9607 |
|
9608 if (!Config::instance()->parse(configName)) |
|
9609 { |
|
9610 err("Error: could not open or read configuration file %s!\n",configName); |
|
9611 cleanUpDoxygen(); |
|
9612 exit(1); |
|
9613 } |
|
9614 |
|
9615 if (updateConfig) |
|
9616 { |
|
9617 generateConfigFile(configName,shortList,TRUE); |
|
9618 cleanUpDoxygen(); |
|
9619 exit(0); |
|
9620 } |
|
9621 |
|
9622 /* Perlmod wants to know the path to the config file.*/ |
|
9623 QFileInfo configFileInfo(configName); |
|
9624 setPerlModDoxyfile(configFileInfo.absFilePath()); |
|
9625 |
|
9626 } |
|
9627 |
|
9628 /** check and resolve config options */ |
|
9629 void checkConfiguration() |
|
9630 { |
|
9631 |
|
9632 Config::instance()->substituteEnvironmentVars(); |
|
9633 Config::instance()->convertStrToVal(); |
|
9634 Config::instance()->check(); |
|
9635 |
|
9636 initWarningFormat(); |
|
9637 } |
|
9638 |
|
9639 /** adjust globals that depend on configuration settings. */ |
|
9640 void adjustConfiguration() |
|
9641 { |
|
9642 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE"); |
|
9643 if (!setTranslator(outputLanguage)) |
|
9644 { |
|
9645 err("Warning: Output language %s not supported! Using English instead.\n", |
|
9646 outputLanguage.data()); |
|
9647 } |
|
9648 QStrList &includePath = Config_getList("INCLUDE_PATH"); |
|
9649 char *s=includePath.first(); |
|
9650 while (s) |
|
9651 { |
|
9652 QFileInfo fi(s); |
|
9653 addSearchDir(fi.absFilePath()); |
|
9654 s=includePath.next(); |
|
9655 } |
|
9656 |
|
9657 /* Set the global html file extension. */ |
|
9658 Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION"); |
|
9659 |
|
9660 |
|
9661 Doxygen::xrefLists->setAutoDelete(TRUE); |
|
9662 |
|
9663 Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || |
|
9664 Config_getBool("CALLER_GRAPH") || |
|
9665 Config_getBool("REFERENCES_RELATION") || |
|
9666 Config_getBool("REFERENCED_BY_RELATION"); |
|
9667 |
|
9668 /************************************************************************** |
|
9669 * Add custom extension mappings |
|
9670 **************************************************************************/ |
|
9671 |
|
9672 QStrList &extMaps = Config_getList("EXTENSION_MAPPING"); |
|
9673 char *mapping = extMaps.first(); |
|
9674 while (mapping) |
|
9675 { |
|
9676 QCString mapStr = mapping; |
|
9677 int i; |
|
9678 if ((i=mapStr.find('='))!=-1) |
|
9679 { |
|
9680 QCString ext=mapStr.left(i).stripWhiteSpace().lower(); |
|
9681 QCString language=mapStr.mid(i+1).stripWhiteSpace().lower(); |
|
9682 if (!updateLanguageMapping(ext,language)) |
|
9683 { |
|
9684 err("Failed to map file extension '%s' to unsupported language '%s'.\n" |
|
9685 "Check the EXTENSION_MAPPING setting in the config file.\n", |
|
9686 ext.data(),language.data()); |
|
9687 } |
|
9688 else |
|
9689 { |
|
9690 msg("Adding custom extension mapping: .%s will be treated as language %s\n", |
|
9691 ext.data(),language.data()); |
|
9692 } |
|
9693 } |
|
9694 mapping = extMaps.next(); |
|
9695 } |
|
9696 |
|
9697 |
|
9698 // add predefined macro name to a dictionary |
|
9699 QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED"); |
|
9700 s=expandAsDefinedList.first(); |
|
9701 while (s) |
|
9702 { |
|
9703 if (Doxygen::expandAsDefinedDict[s]==0) |
|
9704 { |
|
9705 Doxygen::expandAsDefinedDict.insert(s,(void *)666); |
|
9706 } |
|
9707 s=expandAsDefinedList.next(); |
|
9708 } |
|
9709 |
|
9710 // read aliases and store them in a dictionary |
|
9711 readAliases(); |
|
9712 |
|
9713 // store number of spaces in a tab into Doxygen::spaces |
|
9714 int &tabSize = Config_getInt("TAB_SIZE"); |
|
9715 Doxygen::spaces.resize(tabSize+1); |
|
9716 int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' '; |
|
9717 Doxygen::spaces.at(tabSize)='\0'; |
|
9718 } |
|
9719 |
|
9720 #ifdef HAS_SIGNALS |
|
9721 static void stopDoxygen(int) |
|
9722 { |
|
9723 QDir thisDir; |
|
9724 msg("Cleaning up...\n"); |
|
9725 if (!Doxygen::entryDBFileName.isEmpty()) |
|
9726 { |
|
9727 thisDir.remove(Doxygen::entryDBFileName); |
|
9728 } |
|
9729 if (!Doxygen::objDBFileName.isEmpty()) |
|
9730 { |
|
9731 thisDir.remove(Doxygen::objDBFileName); |
|
9732 } |
|
9733 exit(1); |
|
9734 } |
|
9735 #endif |
|
9736 |
|
9737 static void exitDoxygen() |
|
9738 { |
|
9739 if (!g_successfulRun) // premature exit |
|
9740 { |
|
9741 QDir thisDir; |
|
9742 msg("Exiting...\n"); |
|
9743 if (!Doxygen::entryDBFileName.isEmpty()) |
|
9744 { |
|
9745 thisDir.remove(Doxygen::entryDBFileName); |
|
9746 } |
|
9747 if (!Doxygen::objDBFileName.isEmpty()) |
|
9748 { |
|
9749 thisDir.remove(Doxygen::objDBFileName); |
|
9750 } |
|
9751 } |
|
9752 } |
|
9753 |
|
9754 static QCString createOutputDirectory(const QCString &baseDirName, |
|
9755 const char *formatDirOption, |
|
9756 const char *defaultDirName) |
|
9757 { |
|
9758 // Note the & on the next line, we modify the formatDirOption! |
|
9759 QCString &formatDirName = Config_getString(formatDirOption); |
|
9760 if (formatDirName.isEmpty()) |
|
9761 { |
|
9762 formatDirName = baseDirName + defaultDirName; |
|
9763 } |
|
9764 else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':')) |
|
9765 { |
|
9766 formatDirName.prepend(baseDirName+'/'); |
|
9767 } |
|
9768 QDir formatDir(formatDirName); |
|
9769 if (!formatDir.exists() && !formatDir.mkdir(formatDirName)) |
|
9770 { |
|
9771 err("Could not create output directory %s\n", formatDirName.data()); |
|
9772 cleanUpDoxygen(); |
|
9773 exit(1); |
|
9774 } |
|
9775 return formatDirName; |
|
9776 } |
|
9777 |
|
9778 static QCString getQchFileName() |
|
9779 { |
|
9780 QCString const & qchFile = Config_getString("QCH_FILE"); |
|
9781 if (!qchFile.isEmpty()) |
|
9782 { |
|
9783 return qchFile; |
|
9784 } |
|
9785 |
|
9786 QCString const & projectName = Config_getString("PROJECT_NAME"); |
|
9787 QCString const & versionText = Config_getString("PROJECT_NUMBER"); |
|
9788 |
|
9789 return QCString("../qch/") |
|
9790 + (projectName.isEmpty() ? QCString("index") : projectName) |
|
9791 + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText) |
|
9792 + QCString(".qch"); |
|
9793 } |
|
9794 |
|
9795 void searchInputFiles(StringList &inputFiles) |
|
9796 { |
|
9797 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS"); |
|
9798 bool alwaysRecursive = Config_getBool("RECURSIVE"); |
|
9799 StringDict excludeNameDict(1009); |
|
9800 excludeNameDict.setAutoDelete(TRUE); |
|
9801 |
|
9802 // gather names of all files in the include path |
|
9803 msg("Searching for include files...\n"); |
|
9804 QStrList &includePathList = Config_getList("INCLUDE_PATH"); |
|
9805 char *s=includePathList.first(); |
|
9806 while (s) |
|
9807 { |
|
9808 QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS"); |
|
9809 if (pl.count()==0) |
|
9810 { |
|
9811 pl = Config_getList("FILE_PATTERNS"); |
|
9812 } |
|
9813 readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl, |
|
9814 &exclPatterns,0,0, |
|
9815 alwaysRecursive); |
|
9816 s=includePathList.next(); |
|
9817 } |
|
9818 |
|
9819 msg("Searching for example files...\n"); |
|
9820 QStrList &examplePathList = Config_getList("EXAMPLE_PATH"); |
|
9821 s=examplePathList.first(); |
|
9822 while (s) |
|
9823 { |
|
9824 readFileOrDirectory(s,0,Doxygen::exampleNameDict,0, |
|
9825 &Config_getList("EXAMPLE_PATTERNS"), |
|
9826 0,0,0, |
|
9827 (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE"))); |
|
9828 s=examplePathList.next(); |
|
9829 } |
|
9830 |
|
9831 msg("Searching for images...\n"); |
|
9832 QStrList &imagePathList=Config_getList("IMAGE_PATH"); |
|
9833 s=imagePathList.first(); |
|
9834 while (s) |
|
9835 { |
|
9836 readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0, |
|
9837 0,0,0, |
|
9838 alwaysRecursive); |
|
9839 s=imagePathList.next(); |
|
9840 } |
|
9841 |
|
9842 msg("Searching for dot files...\n"); |
|
9843 QStrList &dotFileList=Config_getList("DOTFILE_DIRS"); |
|
9844 s=dotFileList.first(); |
|
9845 while (s) |
|
9846 { |
|
9847 readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0, |
|
9848 0,0,0, |
|
9849 alwaysRecursive); |
|
9850 s=dotFileList.next(); |
|
9851 } |
|
9852 |
|
9853 msg("Searching for files to exclude\n"); |
|
9854 QStrList &excludeList = Config_getList("EXCLUDE"); |
|
9855 s=excludeList.first(); |
|
9856 while (s) |
|
9857 { |
|
9858 readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"), |
|
9859 0,0,&excludeNameDict, |
|
9860 alwaysRecursive, |
|
9861 FALSE); |
|
9862 s=excludeList.next(); |
|
9863 } |
|
9864 |
|
9865 /************************************************************************** |
|
9866 * Determine Input Files * |
|
9867 **************************************************************************/ |
|
9868 |
|
9869 msg("Searching for files to process...\n"); |
|
9870 QDict<void> *killDict = new QDict<void>(10007); |
|
9871 int inputSize=0; |
|
9872 QStrList &inputList=Config_getList("INPUT"); |
|
9873 inputFiles.setAutoDelete(TRUE); |
|
9874 s=inputList.first(); |
|
9875 while (s) |
|
9876 { |
|
9877 QCString path=s; |
|
9878 uint l = path.length(); |
|
9879 // strip trailing slashes |
|
9880 if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1); |
|
9881 |
|
9882 inputSize+=readFileOrDirectory( |
|
9883 path, |
|
9884 Doxygen::inputNameList, |
|
9885 Doxygen::inputNameDict, |
|
9886 &excludeNameDict, |
|
9887 &Config_getList("FILE_PATTERNS"), |
|
9888 &exclPatterns, |
|
9889 &inputFiles,0, |
|
9890 alwaysRecursive, |
|
9891 TRUE, |
|
9892 killDict); |
|
9893 s=inputList.next(); |
|
9894 } |
|
9895 delete killDict; |
|
9896 } |
|
9897 |
|
9898 |
|
9899 void parseInput() |
|
9900 { |
|
9901 atexit(exitDoxygen); |
|
9902 |
|
9903 |
|
9904 /************************************************************************** |
|
9905 * Make sure the output directory exists |
|
9906 **************************************************************************/ |
|
9907 QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY"); |
|
9908 if (outputDirectory.isEmpty()) |
|
9909 { |
|
9910 outputDirectory=QDir::currentDirPath(); |
|
9911 } |
|
9912 else |
|
9913 { |
|
9914 QDir dir(outputDirectory); |
|
9915 if (!dir.exists()) |
|
9916 { |
|
9917 dir.setPath(QDir::currentDirPath()); |
|
9918 if (!dir.mkdir(outputDirectory)) |
|
9919 { |
|
9920 err("Error: tag OUTPUT_DIRECTORY: Output directory `%s' does not " |
|
9921 "exist and cannot be created\n",outputDirectory.data()); |
|
9922 cleanUpDoxygen(); |
|
9923 exit(1); |
|
9924 } |
|
9925 else if (!Config_getBool("QUIET")) |
|
9926 { |
|
9927 err("Notice: Output directory `%s' does not exist. " |
|
9928 "I have created it for you.\n", outputDirectory.data()); |
|
9929 } |
|
9930 dir.cd(outputDirectory); |
|
9931 } |
|
9932 outputDirectory=dir.absPath(); |
|
9933 } |
|
9934 |
|
9935 /************************************************************************** |
|
9936 * Initialize global lists and dictionaries |
|
9937 **************************************************************************/ |
|
9938 |
|
9939 int cacheSize = Config_getInt("SYMBOL_CACHE_SIZE"); |
|
9940 if (cacheSize<0) cacheSize=0; |
|
9941 if (cacheSize>9) cacheSize=9; |
|
9942 Doxygen::symbolCache = new ObjCache(16+cacheSize); // 16 -> room for 65536 elements, |
|
9943 // ~2.0 MByte "overhead" |
|
9944 Doxygen::symbolStorage = new Store; |
|
9945 |
|
9946 #ifdef HAS_SIGNALS |
|
9947 signal(SIGINT, stopDoxygen); |
|
9948 #endif |
|
9949 |
|
9950 uint pid = portable_pid(); |
|
9951 Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid); |
|
9952 Doxygen::objDBFileName.prepend(outputDirectory+"/"); |
|
9953 Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid); |
|
9954 Doxygen::entryDBFileName.prepend(outputDirectory+"/"); |
|
9955 |
|
9956 if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1) |
|
9957 { |
|
9958 err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data()); |
|
9959 exit(1); |
|
9960 } |
|
9961 |
|
9962 |
|
9963 /************************************************************************** |
|
9964 * Initialize some global constants |
|
9965 **************************************************************************/ |
|
9966 |
|
9967 g_compoundKeywordDict.insert("template class",(void *)8); |
|
9968 g_compoundKeywordDict.insert("template struct",(void *)8); |
|
9969 g_compoundKeywordDict.insert("class",(void *)8); |
|
9970 g_compoundKeywordDict.insert("struct",(void *)8); |
|
9971 g_compoundKeywordDict.insert("union",(void *)8); |
|
9972 g_compoundKeywordDict.insert("interface",(void *)8); |
|
9973 g_compoundKeywordDict.insert("exception",(void *)8); |
|
9974 |
|
9975 |
|
9976 /************************************************************************** |
|
9977 * Check/create output directorties * |
|
9978 **************************************************************************/ |
|
9979 |
|
9980 QCString htmlOutput; |
|
9981 bool &generateHtml = Config_getBool("GENERATE_HTML"); |
|
9982 if (generateHtml) |
|
9983 htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html"); |
|
9984 |
|
9985 QCString xmlOutput; |
|
9986 bool &generateXml = Config_getBool("GENERATE_XML"); |
|
9987 if (generateXml) |
|
9988 xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml"); |
|
9989 |
|
9990 QCString xmlDitaOutput; |
|
9991 bool &generateXmlDita = Config_getBool("GENERATE_XML_DITA"); |
|
9992 if (generateXmlDita) |
|
9993 xmlDitaOutput = createOutputDirectory(outputDirectory,"XML_DITA_OUTPUT","/dita"); |
|
9994 |
|
9995 QCString latexOutput; |
|
9996 bool &generateLatex = Config_getBool("GENERATE_LATEX"); |
|
9997 if (generateLatex) |
|
9998 latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex"); |
|
9999 |
|
10000 QCString rtfOutput; |
|
10001 bool &generateRtf = Config_getBool("GENERATE_RTF"); |
|
10002 if (generateRtf) |
|
10003 rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf"); |
|
10004 |
|
10005 QCString manOutput; |
|
10006 bool &generateMan = Config_getBool("GENERATE_MAN"); |
|
10007 if (generateMan) |
|
10008 manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man"); |
|
10009 |
|
10010 |
|
10011 if (Config_getBool("HAVE_DOT")) |
|
10012 { |
|
10013 QCString curFontPath = Config_getString("DOT_FONTPATH"); |
|
10014 if (curFontPath.isEmpty()) |
|
10015 { |
|
10016 portable_getenv("DOTFONTPATH"); |
|
10017 QCString newFontPath = "."; |
|
10018 if (!curFontPath.isEmpty()) |
|
10019 { |
|
10020 newFontPath+=portable_pathListSeparator(); |
|
10021 newFontPath+=curFontPath; |
|
10022 } |
|
10023 portable_setenv("DOTFONTPATH",newFontPath); |
|
10024 } |
|
10025 else |
|
10026 { |
|
10027 portable_setenv("DOTFONTPATH",curFontPath); |
|
10028 } |
|
10029 } |
|
10030 |
|
10031 |
|
10032 |
|
10033 /************************************************************************** |
|
10034 * Handle layout file * |
|
10035 **************************************************************************/ |
|
10036 |
|
10037 LayoutDocManager::instance().init(); |
|
10038 QCString layoutFileName = Config_getString("LAYOUT_FILE"); |
|
10039 bool defaultLayoutUsed = FALSE; |
|
10040 if (layoutFileName.isEmpty()) |
|
10041 { |
|
10042 layoutFileName = "DoxygenLayout.xml"; |
|
10043 defaultLayoutUsed = TRUE; |
|
10044 } |
|
10045 |
|
10046 QFile layoutFile(layoutFileName); |
|
10047 if (layoutFile.open(IO_ReadOnly)) |
|
10048 { |
|
10049 msg("Parsing layout file %s...\n",layoutFileName.data()); |
|
10050 QTextStream t(&layoutFile); |
|
10051 LayoutDocManager::instance().parse(t); |
|
10052 } |
|
10053 else if (!defaultLayoutUsed) |
|
10054 { |
|
10055 err("Warning: failed to open layout file '%s' for reading!\n",layoutFileName.data()); |
|
10056 } |
|
10057 |
|
10058 /************************************************************************** |
|
10059 * Read and preprocess input * |
|
10060 **************************************************************************/ |
|
10061 |
|
10062 // prevent search in the output directories |
|
10063 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS"); |
|
10064 if (generateHtml) exclPatterns.append(htmlOutput); |
|
10065 if (generateXml) exclPatterns.append(xmlOutput); |
|
10066 if (generateXmlDita) exclPatterns.append(xmlDitaOutput); |
|
10067 if (generateLatex) exclPatterns.append(latexOutput); |
|
10068 if (generateRtf) exclPatterns.append(rtfOutput); |
|
10069 if (generateMan) exclPatterns.append(manOutput); |
|
10070 |
|
10071 |
|
10072 searchInputFiles(g_inputFiles); |
|
10073 |
|
10074 // Notice: the order of the function calls below is very important! |
|
10075 |
|
10076 if (Config_getBool("GENERATE_HTML")) |
|
10077 { |
|
10078 readFormulaRepository(); |
|
10079 } |
|
10080 |
|
10081 /************************************************************************** |
|
10082 * Handle Tag Files * |
|
10083 **************************************************************************/ |
|
10084 |
|
10085 g_storage = new FileStorage; |
|
10086 g_storage->setName(Doxygen::entryDBFileName); |
|
10087 if (!g_storage->open(IO_WriteOnly)) |
|
10088 { |
|
10089 err("Failed to create temporary storage file %s\n", |
|
10090 Doxygen::entryDBFileName.data()); |
|
10091 exit(1); |
|
10092 } |
|
10093 Entry *root=new Entry; |
|
10094 EntryNav *rootNav = new EntryNav(0,root); |
|
10095 rootNav->setEntry(root); |
|
10096 msg("Reading and parsing tag files\n"); |
|
10097 |
|
10098 QStrList &tagFileList = Config_getList("TAGFILES"); |
|
10099 char *s=tagFileList.first(); |
|
10100 while (s) |
|
10101 { |
|
10102 readTagFile(root,s); |
|
10103 root->createNavigationIndex(rootNav,g_storage,0); |
|
10104 s=tagFileList.next(); |
|
10105 } |
|
10106 |
|
10107 /************************************************************************** |
|
10108 * Parse source files * |
|
10109 **************************************************************************/ |
|
10110 |
|
10111 parseFiles(root,rootNav); |
|
10112 g_storage->close(); |
|
10113 if (!g_storage->open(IO_ReadOnly)) |
|
10114 { |
|
10115 err("Failed to open temporary storage file %s for reading", |
|
10116 Doxygen::entryDBFileName.data()); |
|
10117 exit(1); |
|
10118 } |
|
10119 |
|
10120 //printNavTree(rootNav,0); |
|
10121 |
|
10122 // we are done with input scanning now, so free up the buffers used by flex |
|
10123 // (can be around 4MB) |
|
10124 preFreeScanner(); |
|
10125 scanFreeScanner(); |
|
10126 pyscanFreeScanner(); |
|
10127 |
|
10128 //delete rootNav; |
|
10129 //g_storage.close(); |
|
10130 //exit(1); |
|
10131 |
|
10132 /************************************************************************** |
|
10133 * Gather information * |
|
10134 **************************************************************************/ |
|
10135 |
|
10136 msg("Building group list...\n"); |
|
10137 buildGroupList(rootNav); |
|
10138 organizeSubGroups(rootNav); |
|
10139 |
|
10140 msg("Building directory list...\n"); |
|
10141 buildDirectories(); |
|
10142 findDirDocumentation(rootNav); |
|
10143 |
|
10144 if (Config_getBool("BUILTIN_STL_SUPPORT")) |
|
10145 { |
|
10146 addSTLClasses(rootNav); |
|
10147 } |
|
10148 |
|
10149 msg("Building namespace list...\n"); |
|
10150 buildNamespaceList(rootNav); |
|
10151 findUsingDirectives(rootNav); |
|
10152 |
|
10153 msg("Building file list...\n"); |
|
10154 buildFileList(rootNav); |
|
10155 //generateFileTree(); |
|
10156 |
|
10157 msg("Building class list...\n"); |
|
10158 buildClassList(rootNav); |
|
10159 |
|
10160 msg("Associating documentation with classes...\n"); |
|
10161 buildClassDocList(rootNav); |
|
10162 |
|
10163 // build list of using declarations here (global list) |
|
10164 buildListOfUsingDecls(rootNav); |
|
10165 |
|
10166 msg("Computing nesting relations for classes...\n"); |
|
10167 resolveClassNestingRelations(); |
|
10168 |
|
10169 // calling buildClassList may result in cached relations that |
|
10170 // become invalid after resolveClassNestingRelations(), that's why |
|
10171 // we need to clear the cache here |
|
10172 Doxygen::lookupCache.clear(); |
|
10173 // we don't need the list of using declaration anymore |
|
10174 g_usingDeclarations.clear(); |
|
10175 |
|
10176 msg("Building example list...\n"); |
|
10177 buildExampleList(rootNav); |
|
10178 |
|
10179 msg("Searching for enumerations...\n"); |
|
10180 findEnums(rootNav); |
|
10181 |
|
10182 // Since buildVarList calls isVarWithConstructor |
|
10183 // and this calls getResolvedClass we need to process |
|
10184 // typedefs first so the relations between classes via typedefs |
|
10185 // are properly resolved. See bug 536385 for an example. |
|
10186 msg("Searching for documented typedefs...\n"); |
|
10187 buildTypedefList(rootNav); |
|
10188 |
|
10189 msg("Searching for members imported via using declarations...\n"); |
|
10190 findUsingDeclImports(rootNav); |
|
10191 // this should be after buildTypedefList in order to properly import |
|
10192 // used typedefs |
|
10193 findUsingDeclarations(rootNav); |
|
10194 |
|
10195 msg("Searching for included using directives...\n"); |
|
10196 findIncludedUsingDirectives(); |
|
10197 |
|
10198 msg("Searching for documented variables...\n"); |
|
10199 buildVarList(rootNav); |
|
10200 |
|
10201 msg("Building member list...\n"); // using class info only ! |
|
10202 buildFunctionList(rootNav); |
|
10203 |
|
10204 msg("Searching for friends...\n"); |
|
10205 findFriends(); |
|
10206 |
|
10207 msg("Searching for documented defines...\n"); |
|
10208 findDefineDocumentation(rootNav); |
|
10209 |
|
10210 findClassEntries(rootNav); |
|
10211 msg("Computing class inheritance relations...\n"); |
|
10212 findInheritedTemplateInstances(); |
|
10213 msg("Computing class usage relations...\n"); |
|
10214 findUsedTemplateInstances(); |
|
10215 |
|
10216 msg("Flushing cached template relations that have become invalid...\n"); |
|
10217 flushCachedTemplateRelations(); |
|
10218 |
|
10219 msg("Creating members for template instances...\n"); |
|
10220 createTemplateInstanceMembers(); |
|
10221 |
|
10222 msg("Computing class relations...\n"); |
|
10223 computeTemplateClassRelations(); |
|
10224 flushUnresolvedRelations(); |
|
10225 if (Config_getBool("OPTIMIZE_OUTPUT_VHDL")) |
|
10226 { |
|
10227 VhdlDocGen::computeVhdlComponentRelations(); |
|
10228 } |
|
10229 else |
|
10230 { |
|
10231 computeClassRelations(); |
|
10232 } |
|
10233 g_classEntries.clear(); |
|
10234 |
|
10235 msg("Add enum values to enums...\n"); |
|
10236 addEnumValuesToEnums(rootNav); |
|
10237 findEnumDocumentation(rootNav); |
|
10238 |
|
10239 msg("Searching for member function documentation...\n"); |
|
10240 findObjCMethodDefinitions(rootNav); |
|
10241 findMemberDocumentation(rootNav); // may introduce new members ! |
|
10242 |
|
10243 transferRelatedFunctionDocumentation(); |
|
10244 transferFunctionDocumentation(); |
|
10245 |
|
10246 msg("Building page list...\n"); |
|
10247 buildPageList(rootNav); |
|
10248 |
|
10249 msg("Search for main page...\n"); |
|
10250 findMainPage(rootNav); |
|
10251 |
|
10252 msg("Computing page relations...\n"); |
|
10253 computePageRelations(rootNav); |
|
10254 checkPageRelations(); |
|
10255 |
|
10256 msg("Determining the scope of groups...\n"); |
|
10257 findGroupScope(rootNav); |
|
10258 |
|
10259 msg("Sorting lists...\n"); |
|
10260 Doxygen::memberNameSDict->sort(); |
|
10261 Doxygen::functionNameSDict->sort(); |
|
10262 Doxygen::hiddenClasses->sort(); |
|
10263 Doxygen::classSDict->sort(); |
|
10264 |
|
10265 msg("Freeing entry tree\n"); |
|
10266 delete rootNav; |
|
10267 g_storage->close(); |
|
10268 delete g_storage; |
|
10269 g_storage=0; |
|
10270 |
|
10271 QDir thisDir; |
|
10272 thisDir.remove(Doxygen::entryDBFileName); |
|
10273 |
|
10274 msg("Determining which enums are documented\n"); |
|
10275 findDocumentedEnumValues(); |
|
10276 |
|
10277 msg("Computing member relations...\n"); |
|
10278 // TODO: This seems to generate an infinite loop |
|
10279 computeMemberRelations(); |
|
10280 |
|
10281 msg("Building full member lists recursively...\n"); |
|
10282 buildCompleteMemberLists(); |
|
10283 |
|
10284 msg("Adding members to member groups.\n"); |
|
10285 addMembersToMemberGroup(); |
|
10286 |
|
10287 if (Config_getBool("DISTRIBUTE_GROUP_DOC")) |
|
10288 { |
|
10289 msg("Distributing member group documentation.\n"); |
|
10290 distributeMemberGroupDocumentation(); |
|
10291 } |
|
10292 |
|
10293 msg("Computing member references...\n"); |
|
10294 computeMemberReferences(); |
|
10295 |
|
10296 if (Config_getBool("INHERIT_DOCS")) |
|
10297 { |
|
10298 msg("Inheriting documentation...\n"); |
|
10299 inheritDocumentation(); |
|
10300 } |
|
10301 |
|
10302 // compute the shortest possible names of all files |
|
10303 // without loosing the uniqueness of the file names. |
|
10304 msg("Generating disk names...\n"); |
|
10305 Doxygen::inputNameList->generateDiskNames(); |
|
10306 |
|
10307 msg("Adding source references...\n"); |
|
10308 addSourceReferences(); |
|
10309 |
|
10310 msg("Adding xrefitems...\n"); |
|
10311 addListReferences(); |
|
10312 generateXRefPages(); |
|
10313 |
|
10314 if (Config_getBool("SHOW_DIRECTORIES") && Config_getBool("DIRECTORY_GRAPH")) |
|
10315 { |
|
10316 msg("Computing dependencies between directories...\n"); |
|
10317 computeDirDependencies(); |
|
10318 } |
|
10319 |
|
10320 msg("Counting data structures...\n"); |
|
10321 countDataStructures(); |
|
10322 |
|
10323 msg("Resolving user defined references...\n"); |
|
10324 resolveUserReferences(); |
|
10325 |
|
10326 msg("Finding anchors and sections in the documentation...\n"); |
|
10327 findSectionsInDocumentation(); |
|
10328 |
|
10329 transferFunctionReferences(); |
|
10330 |
|
10331 msg("Combining using relations...\n"); |
|
10332 combineUsingRelations(); |
|
10333 |
|
10334 msg("Adding members to index pages...\n"); |
|
10335 addMembersToIndex(); |
|
10336 dumpIncludeGraph(); |
|
10337 } |
|
10338 |
|
10339 void generateOutput() |
|
10340 { |
|
10341 /************************************************************************** |
|
10342 * Initialize output generators * |
|
10343 **************************************************************************/ |
|
10344 |
|
10345 //// dump all symbols |
|
10346 //SDict<DefinitionList>::Iterator sdi(Doxygen::symbolMap); |
|
10347 //DefinitionList *dl; |
|
10348 //for (sdi.toFirst();(dl=sdi.current());++sdi) |
|
10349 //{ |
|
10350 // DefinitionListIterator dli(*dl); |
|
10351 // Definition *d; |
|
10352 // printf("Symbol: "); |
|
10353 // for (dli.toFirst();(d=dli.current());++dli) |
|
10354 // { |
|
10355 // printf("%s ",d->qualifiedName().data()); |
|
10356 // } |
|
10357 // printf("\n"); |
|
10358 //} |
|
10359 if (g_dumpSymbolMap) |
|
10360 { |
|
10361 dumpSymbolMap(); |
|
10362 exit(0); |
|
10363 } |
|
10364 |
|
10365 initDocParser(); |
|
10366 |
|
10367 g_outputList = new OutputList(TRUE); |
|
10368 if (Config_getBool("GENERATE_HTML")) |
|
10369 { |
|
10370 g_outputList->add(new HtmlGenerator); |
|
10371 HtmlGenerator::init(); |
|
10372 #if 0 |
|
10373 if (Config_getBool("GENERATE_INDEXLOG")) Doxygen::indexList.addIndex(new IndexLog); |
|
10374 #endif |
|
10375 bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP"); |
|
10376 bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP"); |
|
10377 bool generateQhp = Config_getBool("GENERATE_QHP"); |
|
10378 bool generateTreeView = Config_getBool("GENERATE_TREEVIEW"); |
|
10379 bool generateDocSet = Config_getBool("GENERATE_DOCSET"); |
|
10380 if (generateEclipseHelp) Doxygen::indexList.addIndex(new EclipseHelp); |
|
10381 if (generateHtmlHelp) Doxygen::indexList.addIndex(new HtmlHelp); |
|
10382 if (generateQhp) Doxygen::indexList.addIndex(new Qhp); |
|
10383 if (generateTreeView) Doxygen::indexList.addIndex(new FTVHelp); |
|
10384 if (generateDocSet) Doxygen::indexList.addIndex(new DocSets); |
|
10385 Doxygen::indexList.initialize(); |
|
10386 Doxygen::indexList.addImageFile("tab_r.gif"); |
|
10387 Doxygen::indexList.addImageFile("tab_l.gif"); |
|
10388 Doxygen::indexList.addImageFile("tab_b.gif"); |
|
10389 Doxygen::indexList.addStyleSheetFile("tabs.css"); |
|
10390 Doxygen::indexList.addImageFile("doxygen.png"); |
|
10391 if (Config_getBool("HTML_DYNAMIC_SECTIONS")) HtmlGenerator::generateSectionImages(); |
|
10392 copyStyleSheet(); |
|
10393 } |
|
10394 if (Config_getBool("GENERATE_LATEX")) |
|
10395 { |
|
10396 g_outputList->add(new LatexGenerator); |
|
10397 LatexGenerator::init(); |
|
10398 } |
|
10399 if (Config_getBool("GENERATE_MAN")) |
|
10400 { |
|
10401 g_outputList->add(new ManGenerator); |
|
10402 ManGenerator::init(); |
|
10403 } |
|
10404 if (Config_getBool("GENERATE_RTF")) |
|
10405 { |
|
10406 g_outputList->add(new RTFGenerator); |
|
10407 RTFGenerator::init(); |
|
10408 } |
|
10409 |
|
10410 if (Config_getBool("USE_HTAGS")) |
|
10411 { |
|
10412 Htags::useHtags = TRUE; |
|
10413 QCString htmldir = Config_getString("HTML_OUTPUT"); |
|
10414 if (!Htags::execute(htmldir)) |
|
10415 err("Error: USE_HTAGS is YES but htags(1) failed. \n"); |
|
10416 if (!Htags::loadFilemap(htmldir)) |
|
10417 err("Error: htags(1) ended normally but failed to load the filemap. \n"); |
|
10418 } |
|
10419 |
|
10420 /************************************************************************** |
|
10421 * Generate documentation * |
|
10422 **************************************************************************/ |
|
10423 |
|
10424 QFile *tag=0; |
|
10425 QCString &generateTagFile = Config_getString("GENERATE_TAGFILE"); |
|
10426 if (!generateTagFile.isEmpty()) |
|
10427 { |
|
10428 tag=new QFile(generateTagFile); |
|
10429 if (!tag->open(IO_WriteOnly)) |
|
10430 { |
|
10431 err("Error: cannot open tag file %s for writing\n", |
|
10432 generateTagFile.data() |
|
10433 ); |
|
10434 cleanUpDoxygen(); |
|
10435 exit(1); |
|
10436 } |
|
10437 Doxygen::tagFile.setDevice(tag); |
|
10438 Doxygen::tagFile.setEncoding(QTextStream::UnicodeUTF8); |
|
10439 Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?>" << endl; |
|
10440 Doxygen::tagFile << "<tagfile>" << endl; |
|
10441 } |
|
10442 |
|
10443 if (Config_getBool("GENERATE_HTML")) writeDoxFont(Config_getString("HTML_OUTPUT")); |
|
10444 if (Config_getBool("GENERATE_LATEX")) writeDoxFont(Config_getString("LATEX_OUTPUT")); |
|
10445 if (Config_getBool("GENERATE_RTF")) writeDoxFont(Config_getString("RTF_OUTPUT")); |
|
10446 |
|
10447 msg("Generating style sheet...\n"); |
|
10448 //printf("writing style info\n"); |
|
10449 QCString genString = |
|
10450 theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME")); |
|
10451 g_outputList->writeStyleInfo(0); // write first part |
|
10452 g_outputList->disableAllBut(OutputGenerator::Latex); |
|
10453 g_outputList->parseText(genString); |
|
10454 g_outputList->writeStyleInfo(1); // write second part |
|
10455 //parseText(*g_outputList,theTranslator->trWrittenBy()); |
|
10456 g_outputList->writeStyleInfo(2); // write third part |
|
10457 g_outputList->parseText(genString); |
|
10458 g_outputList->writeStyleInfo(3); // write fourth part |
|
10459 //parseText(*g_outputList,theTranslator->trWrittenBy()); |
|
10460 g_outputList->writeStyleInfo(4); // write last part |
|
10461 g_outputList->enableAll(); |
|
10462 |
|
10463 static bool searchEngine = Config_getBool("SEARCHENGINE"); |
|
10464 static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH"); |
|
10465 |
|
10466 // generate search indices (need to do this before writing other HTML |
|
10467 // pages as these contain a drop down menu with options depending on |
|
10468 // what categories we find in this function. |
|
10469 if (searchEngine) |
|
10470 { |
|
10471 QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search"; |
|
10472 QDir searchDir(searchDirName); |
|
10473 if (!searchDir.exists() && !searchDir.mkdir(searchDirName)) |
|
10474 { |
|
10475 err("Could not create search results directory '%s/search'\n",searchDirName.data()); |
|
10476 return; |
|
10477 } |
|
10478 HtmlGenerator::writeSearchData(searchDirName); |
|
10479 writeSearchStyleSheet(); |
|
10480 if (serverBasedSearch) |
|
10481 { |
|
10482 } |
|
10483 else |
|
10484 { |
|
10485 writeJavascriptSearchIndex(); |
|
10486 } |
|
10487 } |
|
10488 |
|
10489 //statistics(); |
|
10490 |
|
10491 // count the number of documented elements in the lists we have built. |
|
10492 // If the result is 0 we do not generate the lists and omit the |
|
10493 // corresponding links in the index. |
|
10494 msg("Generating index page...\n"); |
|
10495 writeIndex(*g_outputList); |
|
10496 |
|
10497 msg("Generating page index...\n"); |
|
10498 writePageIndex(*g_outputList); |
|
10499 |
|
10500 msg("Generating example documentation...\n"); |
|
10501 generateExampleDocs(); |
|
10502 |
|
10503 msg("Generating file sources...\n"); |
|
10504 if (!Htags::useHtags) |
|
10505 { |
|
10506 generateFileSources(); |
|
10507 } |
|
10508 |
|
10509 msg("Generating file documentation...\n"); |
|
10510 generateFileDocs(); |
|
10511 |
|
10512 msg("Generating page documentation...\n"); |
|
10513 generatePageDocs(); |
|
10514 |
|
10515 msg("Generating group documentation...\n"); |
|
10516 generateGroupDocs(); |
|
10517 |
|
10518 msg("Generating group index...\n"); |
|
10519 writeGroupIndex(*g_outputList); |
|
10520 |
|
10521 msg("Generating class documentation...\n"); |
|
10522 generateClassDocs(); |
|
10523 |
|
10524 if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY")) |
|
10525 { |
|
10526 msg("Generating graphical class hierarchy...\n"); |
|
10527 writeGraphicalClassHierarchy(*g_outputList); |
|
10528 } |
|
10529 |
|
10530 msg("Generating namespace index...\n"); |
|
10531 generateNamespaceDocs(); |
|
10532 |
|
10533 msg("Generating namespace member index...\n"); |
|
10534 writeNamespaceMemberIndex(*g_outputList); |
|
10535 |
|
10536 if (Config_getBool("GENERATE_LEGEND")) |
|
10537 { |
|
10538 msg("Generating graph info page...\n"); |
|
10539 writeGraphInfo(*g_outputList); |
|
10540 } |
|
10541 |
|
10542 if (Config_getBool("SHOW_DIRECTORIES")) |
|
10543 { |
|
10544 msg("Generating directory documentation...\n"); |
|
10545 generateDirDocs(*g_outputList); |
|
10546 } |
|
10547 |
|
10548 msg("Generating file index...\n"); |
|
10549 writeFileIndex(*g_outputList); |
|
10550 |
|
10551 if (Config_getBool("SHOW_DIRECTORIES")) |
|
10552 { |
|
10553 msg("Generating directory index...\n"); |
|
10554 writeDirIndex(*g_outputList); |
|
10555 } |
|
10556 |
|
10557 msg("Generating example index...\n"); |
|
10558 writeExampleIndex(*g_outputList); |
|
10559 |
|
10560 msg("Generating file member index...\n"); |
|
10561 writeFileMemberIndex(*g_outputList); |
|
10562 |
|
10563 |
|
10564 //writeDirDependencyGraph(Config_getString("HTML_OUTPUT")); |
|
10565 |
|
10566 if (Config_getBool("GENERATE_RTF")) |
|
10567 { |
|
10568 msg("Combining RTF output...\n"); |
|
10569 if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf")) |
|
10570 { |
|
10571 err("An error occurred during post-processing the RTF files!\n"); |
|
10572 } |
|
10573 } |
|
10574 |
|
10575 if (Doxygen::formulaList.count()>0 && Config_getBool("GENERATE_HTML")) |
|
10576 { |
|
10577 msg("Generating bitmaps for formulas in HTML...\n"); |
|
10578 Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT")); |
|
10579 } |
|
10580 |
|
10581 //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_HTMLHELP")) |
|
10582 //{ |
|
10583 // HtmlHelp::getInstance()->finalize(); |
|
10584 //} |
|
10585 //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_TREEVIEW")) |
|
10586 //{ |
|
10587 // FTVHelp::getInstance()->finalize(); |
|
10588 //} |
|
10589 |
|
10590 Doxygen::indexList.finalize(); |
|
10591 |
|
10592 if (!Config_getString("GENERATE_TAGFILE").isEmpty()) |
|
10593 { |
|
10594 Doxygen::tagFile << "</tagfile>" << endl; |
|
10595 delete tag; |
|
10596 } |
|
10597 |
|
10598 if (Config_getBool("DOT_CLEANUP")) |
|
10599 { |
|
10600 if (Config_getBool("GENERATE_HTML")) |
|
10601 removeDoxFont(Config_getString("HTML_OUTPUT")); |
|
10602 if (Config_getBool("GENERATE_RTF")) |
|
10603 removeDoxFont(Config_getString("RTF_OUTPUT")); |
|
10604 if (Config_getBool("GENERATE_LATEX")) |
|
10605 removeDoxFont(Config_getString("LATEX_OUTPUT")); |
|
10606 } |
|
10607 |
|
10608 if (Config_getBool("GENERATE_XML")) |
|
10609 { |
|
10610 msg("Generating XML output...\n"); |
|
10611 generateXML(); |
|
10612 } |
|
10613 if (Config_getBool("GENERATE_XML_DITA")) |
|
10614 { |
|
10615 msg("Generating XML DITA output...\n"); |
|
10616 generateXMLDITA(); |
|
10617 } |
|
10618 if (Config_getBool("GENERATE_AUTOGEN_DEF")) |
|
10619 { |
|
10620 msg("Generating AutoGen DEF output...\n"); |
|
10621 generateDEF(); |
|
10622 } |
|
10623 if (Config_getBool("GENERATE_PERLMOD")) |
|
10624 { |
|
10625 msg("Generating Perl module output...\n"); |
|
10626 generatePerlMod(); |
|
10627 } |
|
10628 if (Config_getBool("GENERATE_HTML") && |
|
10629 Config_getBool("GENERATE_HTMLHELP") && |
|
10630 !Config_getString("HHC_LOCATION").isEmpty()) |
|
10631 { |
|
10632 msg("Running html help compiler...\n"); |
|
10633 QString oldDir = QDir::currentDirPath(); |
|
10634 QDir::setCurrent(Config_getString("HTML_OUTPUT")); |
|
10635 if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE)) |
|
10636 { |
|
10637 err("Error: failed to run html help compiler on index.hhp\n"); |
|
10638 } |
|
10639 QDir::setCurrent(oldDir); |
|
10640 } |
|
10641 if ( Config_getBool("GENERATE_HTML") && |
|
10642 Config_getBool("GENERATE_QHP") && |
|
10643 !Config_getString("QHG_LOCATION").isEmpty()) |
|
10644 { |
|
10645 msg("Running qhelpgenerator...\n"); |
|
10646 QCString const qhpFileName = Qhp::getQhpFileName(); |
|
10647 QCString const qchFileName = getQchFileName(); |
|
10648 |
|
10649 QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data()); |
|
10650 QString const oldDir = QDir::currentDirPath(); |
|
10651 QDir::setCurrent(Config_getString("HTML_OUTPUT")); |
|
10652 if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE)) |
|
10653 { |
|
10654 err("Error: failed to run qhelpgenerator on index.qhp\n"); |
|
10655 } |
|
10656 QDir::setCurrent(oldDir); |
|
10657 } |
|
10658 |
|
10659 if (Config_getBool("GENERATE_HTML") && searchEngine && serverBasedSearch) |
|
10660 { |
|
10661 msg("Generating search index\n"); |
|
10662 HtmlGenerator::writeSearchPage(); |
|
10663 Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx"); |
|
10664 } |
|
10665 |
|
10666 if (Debug::isFlagSet(Debug::Time)) |
|
10667 { |
|
10668 msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n", |
|
10669 ((double)Doxygen::runningTime.elapsed())/1000.0, |
|
10670 portable_getSysElapsedTime() |
|
10671 ); |
|
10672 } |
|
10673 |
|
10674 /************************************************************************** |
|
10675 * Start cleaning up * |
|
10676 **************************************************************************/ |
|
10677 |
|
10678 //Doxygen::symbolCache->printStats(); |
|
10679 //Doxygen::symbolStorage->printStats(); |
|
10680 cleanUpDoxygen(); |
|
10681 |
|
10682 finializeDocParser(); |
|
10683 Doxygen::symbolStorage->close(); |
|
10684 QDir thisDir; |
|
10685 thisDir.remove(Doxygen::objDBFileName); |
|
10686 Config::deleteInstance(); |
|
10687 QTextCodec::deleteAllCodecs(); |
|
10688 delete Doxygen::symbolCache; |
|
10689 delete Doxygen::symbolMap; |
|
10690 delete Doxygen::symbolStorage; |
|
10691 g_successfulRun=TRUE; |
|
10692 msg("generateOutput() exiting.\n"); |
|
10693 } |
|
10694 |