Root/
Source at commit 1322 created 12 years 8 months ago. By meklort, Add doxygen to utils folder | |
---|---|
1 | /******************************************************************************␊ |
2 | *␊ |
3 | * Copyright (C) 1997-2011 by Dimitri van Heesch.␊ |
4 | *␊ |
5 | * Permission to use, copy, modify, and distribute this software and its␊ |
6 | * documentation under the terms of the GNU General Public License is hereby ␊ |
7 | * granted. No representations are made about the suitability of this software ␊ |
8 | * for any purpose. It is provided "as is" without express or implied warranty.␊ |
9 | * See the GNU General Public License for more details.␊ |
10 | *␊ |
11 | * Documents produced by Doxygen are derivative works derived from the␊ |
12 | * input used in their production; they are not affected by this license.␊ |
13 | *␊ |
14 | */␊ |
15 | ␊ |
16 | #include "qtbc.h"␊ |
17 | #include <qfileinfo.h>␊ |
18 | #include <qfile.h>␊ |
19 | #include <qdir.h>␊ |
20 | #include <qdict.h>␊ |
21 | #include <qregexp.h>␊ |
22 | #include <qstrlist.h>␊ |
23 | #include <stdio.h>␊ |
24 | #include <stdlib.h>␊ |
25 | #include <sys/stat.h>␊ |
26 | #include <qtextcodec.h>␊ |
27 | #include <unistd.h>␊ |
28 | #include <errno.h>␊ |
29 | ␊ |
30 | #include "version.h"␊ |
31 | #include "doxygen.h"␊ |
32 | #include "scanner.h"␊ |
33 | #include "entry.h"␊ |
34 | #include "index.h"␊ |
35 | #include "logos.h"␊ |
36 | #include "instdox.h"␊ |
37 | #include "message.h"␊ |
38 | #include "config.h"␊ |
39 | #include "util.h"␊ |
40 | #include "pre.h"␊ |
41 | #include "tagreader.h"␊ |
42 | #include "dot.h"␊ |
43 | #include "msc.h"␊ |
44 | #include "docparser.h"␊ |
45 | #include "dirdef.h"␊ |
46 | #include "outputlist.h"␊ |
47 | #include "declinfo.h"␊ |
48 | #include "htmlgen.h"␊ |
49 | #include "latexgen.h"␊ |
50 | #include "mangen.h"␊ |
51 | #include "language.h"␊ |
52 | #include "debug.h"␊ |
53 | #include "htmlhelp.h"␊ |
54 | #include "qhp.h"␊ |
55 | #include "indexlog.h"␊ |
56 | #include "ftvhelp.h"␊ |
57 | #include "defargs.h"␊ |
58 | #include "rtfgen.h"␊ |
59 | #include "xmlgen.h"␊ |
60 | #include "defgen.h"␊ |
61 | #include "perlmodgen.h"␊ |
62 | #include "reflist.h"␊ |
63 | #include "pagedef.h"␊ |
64 | #include "bufstr.h"␊ |
65 | #include "commentcnv.h"␊ |
66 | #include "cmdmapper.h"␊ |
67 | #include "searchindex.h"␊ |
68 | #include "parserintf.h"␊ |
69 | #include "htags.h"␊ |
70 | #include "pyscanner.h"␊ |
71 | #include "fortranscanner.h"␊ |
72 | #include "dbusxmlscanner.h"␊ |
73 | #include "code.h"␊ |
74 | #include "objcache.h"␊ |
75 | #include "store.h"␊ |
76 | #include "marshal.h"␊ |
77 | #include "portable.h"␊ |
78 | #include "vhdlscanner.h"␊ |
79 | #include "vhdldocgen.h"␊ |
80 | #include "eclipsehelp.h"␊ |
81 | ␊ |
82 | #include "layout.h"␊ |
83 | ␊ |
84 | #define RECURSE_ENTRYTREE(func,var) \␊ |
85 | do { if (var->children()) { \␊ |
86 | EntryNavListIterator eli(*var->children()); \␊ |
87 | for (;eli.current();++eli) func(eli.current()); \␊ |
88 | } } while(0) ␊ |
89 | ␊ |
90 | ␊ |
91 | #if !defined(_WIN32) || defined(__CYGWIN__)␊ |
92 | #include <signal.h>␊ |
93 | #define HAS_SIGNALS␊ |
94 | #endif␊ |
95 | ␊ |
96 | // globally accessible variables␊ |
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 | FileNameDict *Doxygen::mscFileNameDict = 0; // dot files␊ |
117 | StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases␊ |
118 | StringDict Doxygen::tagDestinationDict(257); // all tag locations␊ |
119 | QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded␊ |
120 | QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading␊ |
121 | PageDef *Doxygen::mainPage = 0;␊ |
122 | bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?␊ |
123 | FTextStream Doxygen::tagFile;␊ |
124 | NamespaceDef *Doxygen::globalScope = 0;␊ |
125 | QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists␊ |
126 | bool Doxygen::parseSourcesNeeded = FALSE;␊ |
127 | QTime Doxygen::runningTime;␊ |
128 | SearchIndex * Doxygen::searchIndex=0;␊ |
129 | QDict<DefinitionIntf> *Doxygen::symbolMap;␊ |
130 | bool Doxygen::outputToWizard=FALSE;␊ |
131 | QDict<int> * Doxygen::htmlDirMap = 0;␊ |
132 | QCache<LookupInfo> Doxygen::lookupCache(50000,50000);␊ |
133 | DirSDict *Doxygen::directories;␊ |
134 | SDict<DirRelation> Doxygen::dirRelations(257);␊ |
135 | ParserManager *Doxygen::parserManager = 0;␊ |
136 | QCString Doxygen::htmlFileExtension;␊ |
137 | bool Doxygen::suppressDocWarnings = FALSE;␊ |
138 | ObjCache *Doxygen::symbolCache = 0;␊ |
139 | Store *Doxygen::symbolStorage;␊ |
140 | QCString Doxygen::objDBFileName;␊ |
141 | QCString Doxygen::entryDBFileName;␊ |
142 | bool Doxygen::gatherDefines = TRUE;␊ |
143 | IndexList Doxygen::indexList;␊ |
144 | int Doxygen::subpageNestingLevel = 0;␊ |
145 | bool Doxygen::userComments = FALSE;␊ |
146 | QCString Doxygen::spaces;␊ |
147 | ␊ |
148 | // locally accessible globals␊ |
149 | static QDict<EntryNav> g_classEntries(1009);␊ |
150 | static StringList g_inputFiles; ␊ |
151 | static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds␊ |
152 | static OutputList *g_outputList = 0; // list of output generating objects␊ |
153 | static QDict<FileDef> g_usingDeclarations(1009); // used classes␊ |
154 | static FileStorage *g_storage = 0;␊ |
155 | static bool g_successfulRun = FALSE;␊ |
156 | static bool g_dumpSymbolMap = FALSE;␊ |
157 | static bool g_dumpConfigAsXML = FALSE;␊ |
158 | ␊ |
159 | ␊ |
160 | ␊ |
161 | void clearAll()␊ |
162 | {␊ |
163 | g_inputFiles.clear(); ␊ |
164 | //g_excludeNameDict.clear(); ␊ |
165 | //delete g_outputList; g_outputList=0;␊ |
166 | ␊ |
167 | Doxygen::classSDict->clear(); ␊ |
168 | Doxygen::namespaceSDict->clear(); ␊ |
169 | Doxygen::pageSDict->clear(); ␊ |
170 | Doxygen::exampleSDict->clear(); ␊ |
171 | Doxygen::inputNameList->clear(); ␊ |
172 | Doxygen::formulaList.clear(); ␊ |
173 | Doxygen::sectionDict.clear(); ␊ |
174 | Doxygen::inputNameDict->clear(); ␊ |
175 | Doxygen::includeNameDict->clear(); ␊ |
176 | Doxygen::exampleNameDict->clear(); ␊ |
177 | Doxygen::imageNameDict->clear(); ␊ |
178 | Doxygen::dotFileNameDict->clear(); ␊ |
179 | Doxygen::mscFileNameDict->clear(); ␊ |
180 | Doxygen::formulaDict.clear(); ␊ |
181 | Doxygen::formulaNameDict.clear(); ␊ |
182 | Doxygen::tagDestinationDict.clear();␊ |
183 | delete Doxygen::mainPage; Doxygen::mainPage=0;␊ |
184 | }␊ |
185 | ␊ |
186 | void statistics()␊ |
187 | {␊ |
188 | fprintf(stderr,"--- inputNameDict stats ----\n");␊ |
189 | Doxygen::inputNameDict->statistics();␊ |
190 | fprintf(stderr,"--- includeNameDict stats ----\n");␊ |
191 | Doxygen::includeNameDict->statistics();␊ |
192 | fprintf(stderr,"--- exampleNameDict stats ----\n");␊ |
193 | Doxygen::exampleNameDict->statistics();␊ |
194 | fprintf(stderr,"--- imageNameDict stats ----\n");␊ |
195 | Doxygen::imageNameDict->statistics();␊ |
196 | fprintf(stderr,"--- dotFileNameDict stats ----\n");␊ |
197 | Doxygen::dotFileNameDict->statistics();␊ |
198 | fprintf(stderr,"--- mscFileNameDict stats ----\n");␊ |
199 | Doxygen::mscFileNameDict->statistics();␊ |
200 | //fprintf(stderr,"--- g_excludeNameDict stats ----\n");␊ |
201 | //g_excludeNameDict.statistics();␊ |
202 | fprintf(stderr,"--- aliasDict stats ----\n");␊ |
203 | Doxygen::aliasDict.statistics();␊ |
204 | fprintf(stderr,"--- typedefDict stats ----\n");␊ |
205 | fprintf(stderr,"--- namespaceAliasDict stats ----\n");␊ |
206 | Doxygen::namespaceAliasDict.statistics();␊ |
207 | fprintf(stderr,"--- formulaDict stats ----\n");␊ |
208 | Doxygen::formulaDict.statistics();␊ |
209 | fprintf(stderr,"--- formulaNameDict stats ----\n");␊ |
210 | Doxygen::formulaNameDict.statistics();␊ |
211 | fprintf(stderr,"--- tagDestinationDict stats ----\n");␊ |
212 | Doxygen::tagDestinationDict.statistics();␊ |
213 | fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");␊ |
214 | g_compoundKeywordDict.statistics();␊ |
215 | fprintf(stderr,"--- expandAsDefinedDict stats ----\n");␊ |
216 | Doxygen::expandAsDefinedDict.statistics();␊ |
217 | fprintf(stderr,"--- memGrpInfoDict stats ----\n");␊ |
218 | Doxygen::memGrpInfoDict.statistics();␊ |
219 | }␊ |
220 | ␊ |
221 | ␊ |
222 | ␊ |
223 | static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,␊ |
224 | ArgumentList *al,bool over_load,NamespaceSDict *nl=0);␊ |
225 | static void findMember(EntryNav *rootNav,␊ |
226 | QCString funcDecl,␊ |
227 | bool overloaded,␊ |
228 | bool isFunc␊ |
229 | );␊ |
230 | ␊ |
231 | ␊ |
232 | struct STLInfo␊ |
233 | {␊ |
234 | const char *className;␊ |
235 | const char *baseClass1;␊ |
236 | const char *baseClass2;␊ |
237 | const char *templType1;␊ |
238 | const char *templName1;␊ |
239 | const char *templType2;␊ |
240 | const char *templName2;␊ |
241 | bool virtualInheritance;␊ |
242 | bool iterators;␊ |
243 | };␊ |
244 | ␊ |
245 | static STLInfo g_stlinfo[] =␊ |
246 | {␊ |
247 | // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators␊ |
248 | { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },␊ |
249 | { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE },␊ |
250 | { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
251 | { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE },␊ |
252 | { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },␊ |
253 | { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },␊ |
254 | { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE },␊ |
255 | { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },␊ |
256 | { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },␊ |
257 | { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },␊ |
258 | { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },␊ |
259 | { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },␊ |
260 | { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },␊ |
261 | { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
262 | { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
263 | { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
264 | { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
265 | { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
266 | { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
267 | { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
268 | { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
269 | { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
270 | { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
271 | { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
272 | { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
273 | { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
274 | { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
275 | { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
276 | { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
277 | { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
278 | { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
279 | { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE },␊ |
280 | { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE },␊ |
281 | { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE },␊ |
282 | { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
283 | { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE },␊ |
284 | { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },␊ |
285 | { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },␊ |
286 | { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },␊ |
287 | { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },␊ |
288 | { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },␊ |
289 | { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },␊ |
290 | { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },␊ |
291 | { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },␊ |
292 | { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },␊ |
293 | { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },␊ |
294 | { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },␊ |
295 | { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
296 | { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
297 | { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
298 | { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
299 | { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
300 | { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
301 | { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
302 | { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
303 | { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
304 | { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
305 | { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
306 | { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
307 | { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
308 | { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
309 | { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },␊ |
310 | { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE }␊ |
311 | };␊ |
312 | ␊ |
313 | static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)␊ |
314 | {␊ |
315 | Entry *memEntry = new Entry;␊ |
316 | memEntry->name = name;␊ |
317 | memEntry->type = type;␊ |
318 | memEntry->protection = Private;␊ |
319 | memEntry->section = Entry::VARIABLE_SEC;␊ |
320 | memEntry->brief = "STL member";␊ |
321 | memEntry->hidden = FALSE; ␊ |
322 | memEntry->artificial = TRUE;␊ |
323 | //memEntry->parent = root;␊ |
324 | //root->addSubEntry(memEntry);␊ |
325 | EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);␊ |
326 | memEntryNav->setEntry(memEntry);␊ |
327 | rootNav->addChild(memEntryNav);␊ |
328 | }␊ |
329 | ␊ |
330 | static void addSTLIterator(EntryNav *classEntryNav,const char *name)␊ |
331 | {␊ |
332 | Entry *iteratorClassEntry = new Entry;␊ |
333 | iteratorClassEntry->fileName = "[STL]";␊ |
334 | iteratorClassEntry->startLine = 1;␊ |
335 | iteratorClassEntry->name = name;␊ |
336 | iteratorClassEntry->section = Entry::CLASS_SEC;␊ |
337 | iteratorClassEntry->brief = "STL iterator class";␊ |
338 | iteratorClassEntry->hidden = FALSE;␊ |
339 | iteratorClassEntry->artificial= TRUE;␊ |
340 | EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);␊ |
341 | iteratorClassEntryNav->setEntry(iteratorClassEntry);␊ |
342 | classEntryNav->addChild(iteratorClassEntryNav);␊ |
343 | }␊ |
344 | ␊ |
345 | ␊ |
346 | static void addSTLClasses(EntryNav *rootNav)␊ |
347 | {␊ |
348 | Entry *namespaceEntry = new Entry;␊ |
349 | namespaceEntry->fileName = "[STL]";␊ |
350 | namespaceEntry->startLine = 1;␊ |
351 | //namespaceEntry->parent = rootNav->entry();␊ |
352 | namespaceEntry->name = "std";␊ |
353 | namespaceEntry->section = Entry::NAMESPACE_SEC;␊ |
354 | namespaceEntry->brief = "STL namespace";␊ |
355 | namespaceEntry->hidden = FALSE;␊ |
356 | namespaceEntry->artificial= TRUE;␊ |
357 | //root->addSubEntry(namespaceEntry);␊ |
358 | EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);␊ |
359 | namespaceEntryNav->setEntry(namespaceEntry);␊ |
360 | rootNav->addChild(namespaceEntryNav);␊ |
361 | ␊ |
362 | STLInfo *info = g_stlinfo;␊ |
363 | while (info->className)␊ |
364 | {␊ |
365 | //printf("Adding STL class %s\n",info->className);␊ |
366 | QCString fullName = info->className;␊ |
367 | fullName.prepend("std::");␊ |
368 | ␊ |
369 | // add fake Entry for the class␊ |
370 | Entry *classEntry = new Entry;␊ |
371 | classEntry->fileName = "[STL]";␊ |
372 | classEntry->startLine = 1;␊ |
373 | classEntry->name = fullName;␊ |
374 | //classEntry->parent = namespaceEntry;␊ |
375 | classEntry->section = Entry::CLASS_SEC;␊ |
376 | classEntry->brief = "STL class";␊ |
377 | classEntry->hidden = FALSE;␊ |
378 | classEntry->artificial= TRUE;␊ |
379 | //namespaceEntry->addSubEntry(classEntry);␊ |
380 | EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);␊ |
381 | classEntryNav->setEntry(classEntry);␊ |
382 | namespaceEntryNav->addChild(classEntryNav);␊ |
383 | ␊ |
384 | // add template arguments to class␊ |
385 | if (info->templType1)␊ |
386 | {␊ |
387 | ArgumentList *al = new ArgumentList;␊ |
388 | Argument *a=new Argument;␊ |
389 | a->type="typename";␊ |
390 | a->name=info->templType1;␊ |
391 | al->append(a);␊ |
392 | if (info->templType2) // another template argument␊ |
393 | {␊ |
394 | a=new Argument;␊ |
395 | a->type="typename";␊ |
396 | a->name=info->templType2;␊ |
397 | al->append(a);␊ |
398 | }␊ |
399 | classEntry->tArgLists = new QList<ArgumentList>;␊ |
400 | classEntry->tArgLists->setAutoDelete(TRUE);␊ |
401 | classEntry->tArgLists->append(al);␊ |
402 | }␊ |
403 | // add member variables␊ |
404 | if (info->templName1)␊ |
405 | {␊ |
406 | addSTLMember(classEntryNav,info->templType1,info->templName1);␊ |
407 | }␊ |
408 | if (info->templName2)␊ |
409 | {␊ |
410 | addSTLMember(classEntryNav,info->templType2,info->templName2);␊ |
411 | }␊ |
412 | if (info->baseClass1)␊ |
413 | {␊ |
414 | classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));␊ |
415 | }␊ |
416 | if (info->baseClass2)␊ |
417 | {␊ |
418 | classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));␊ |
419 | }␊ |
420 | if (info->iterators)␊ |
421 | {␊ |
422 | // add iterator class␊ |
423 | addSTLIterator(classEntryNav,fullName+"::iterator");␊ |
424 | addSTLIterator(classEntryNav,fullName+"::const_iterator");␊ |
425 | addSTLIterator(classEntryNav,fullName+"::reverse_iterator");␊ |
426 | addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");␊ |
427 | }␊ |
428 | info++;␊ |
429 | }␊ |
430 | }␊ |
431 | ␊ |
432 | //----------------------------------------------------------------------------␊ |
433 | ␊ |
434 | static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,␊ |
435 | FileDef *fileScope=0);␊ |
436 | ␊ |
437 | static void addPageToContext(PageDef *pd,EntryNav *rootNav)␊ |
438 | {␊ |
439 | if (rootNav->parent()) // add the page to it's scope␊ |
440 | {␊ |
441 | QCString scope = rootNav->parent()->name();␊ |
442 | if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)␊ |
443 | {␊ |
444 | scope=substitute(scope,".","::");␊ |
445 | }␊ |
446 | scope = stripAnonymousNamespaceScope(scope);␊ |
447 | scope+="::"+pd->name();␊ |
448 | Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);␊ |
449 | if (d) ␊ |
450 | {␊ |
451 | pd->setPageScope(d);␊ |
452 | }␊ |
453 | }␊ |
454 | }␊ |
455 | ␊ |
456 | static void addRelatedPage(EntryNav *rootNav)␊ |
457 | {␊ |
458 | Entry *root = rootNav->entry();␊ |
459 | GroupDef *gd=0;␊ |
460 | QListIterator<Grouping> gli(*root->groups);␊ |
461 | Grouping *g;␊ |
462 | for (;(g=gli.current());++gli)␊ |
463 | {␊ |
464 | if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;␊ |
465 | }␊ |
466 | //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);␊ |
467 | QCString doc;␊ |
468 | if (root->brief.isEmpty())␊ |
469 | {␊ |
470 | doc=root->doc+root->inbodyDocs;␊ |
471 | }␊ |
472 | else␊ |
473 | {␊ |
474 | doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;␊ |
475 | }␊ |
476 | PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,␊ |
477 | root->fileName,root->startLine,␊ |
478 | root->sli,␊ |
479 | gd,rootNav->tagInfo()␊ |
480 | );␊ |
481 | if (pd)␊ |
482 | {␊ |
483 | pd->addSectionsToDefinition(root->anchors);␊ |
484 | addPageToContext(pd,rootNav);␊ |
485 | }␊ |
486 | }␊ |
487 | ␊ |
488 | static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)␊ |
489 | {␊ |
490 | if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && ␊ |
491 | ((!includeExternal && rootNav->tagInfo()==0) ||␊ |
492 | ( includeExternal && rootNav->tagInfo()!=0))␊ |
493 | )␊ |
494 | {␊ |
495 | rootNav->loadEntry(g_storage);␊ |
496 | Entry *root = rootNav->entry();␊ |
497 | ␊ |
498 | if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||␊ |
499 | (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))␊ |
500 | {␊ |
501 | GroupDef *gd = Doxygen::groupSDict->find(root->name);␊ |
502 | //printf("Processing group '%s': add=%d ext=%d gd=%p\n",␊ |
503 | // root->type.data(),additional,includeExternal,gd);␊ |
504 | ␊ |
505 | if (gd)␊ |
506 | {␊ |
507 | if ( !gd->hasGroupTitle() )␊ |
508 | {␊ |
509 | gd->setGroupTitle( root->type );␊ |
510 | }␊ |
511 | else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )␊ |
512 | {␊ |
513 | warn( root->fileName,root->startLine,␊ |
514 | "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",␊ |
515 | qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );␊ |
516 | }␊ |
517 | gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
518 | gd->setDocumentation( root->doc, root->docFile, root->docLine );␊ |
519 | gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );␊ |
520 | gd->addSectionsToDefinition(root->anchors);␊ |
521 | gd->setRefItems(root->sli);␊ |
522 | }␊ |
523 | else␊ |
524 | {␊ |
525 | if (rootNav->tagInfo())␊ |
526 | {␊ |
527 | gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);␊ |
528 | gd->setReference(rootNav->tagInfo()->tagName);␊ |
529 | }␊ |
530 | else␊ |
531 | {␊ |
532 | gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);␊ |
533 | }␊ |
534 | gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
535 | gd->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
536 | gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );␊ |
537 | gd->addSectionsToDefinition(root->anchors);␊ |
538 | Doxygen::groupSDict->append(root->name,gd);␊ |
539 | gd->setRefItems(root->sli);␊ |
540 | }␊ |
541 | }␊ |
542 | ␊ |
543 | rootNav->releaseEntry();␊ |
544 | }␊ |
545 | if (rootNav->children())␊ |
546 | {␊ |
547 | EntryNavListIterator eli(*rootNav->children());␊ |
548 | EntryNav *e;␊ |
549 | for (;(e=eli.current());++eli)␊ |
550 | {␊ |
551 | buildGroupListFiltered(e,additional,includeExternal);␊ |
552 | }␊ |
553 | }␊ |
554 | }␊ |
555 | ␊ |
556 | static void buildGroupList(EntryNav *rootNav)␊ |
557 | {␊ |
558 | // --- first process only local groups␊ |
559 | // first process the @defgroups blocks␊ |
560 | buildGroupListFiltered(rootNav,FALSE,FALSE);␊ |
561 | // then process the @addtogroup, @weakgroup blocks␊ |
562 | buildGroupListFiltered(rootNav,TRUE,FALSE);␊ |
563 | ␊ |
564 | // --- then also process external groups␊ |
565 | // first process the @defgroups blocks␊ |
566 | buildGroupListFiltered(rootNav,FALSE,TRUE);␊ |
567 | // then process the @addtogroup, @weakgroup blocks␊ |
568 | buildGroupListFiltered(rootNav,TRUE,TRUE);␊ |
569 | }␊ |
570 | ␊ |
571 | static void findGroupScope(EntryNav *rootNav)␊ |
572 | {␊ |
573 | if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() && ␊ |
574 | rootNav->parent() && !rootNav->parent()->name().isEmpty())␊ |
575 | {␊ |
576 | GroupDef *gd;␊ |
577 | if ((gd=Doxygen::groupSDict->find(rootNav->name())))␊ |
578 | {␊ |
579 | QCString scope = rootNav->parent()->name();␊ |
580 | if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)␊ |
581 | {␊ |
582 | scope=substitute(scope,".","::");␊ |
583 | }␊ |
584 | scope = stripAnonymousNamespaceScope(scope);␊ |
585 | scope+="::"+gd->name();␊ |
586 | Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);␊ |
587 | if (d) ␊ |
588 | {␊ |
589 | gd->setGroupScope(d);␊ |
590 | }␊ |
591 | }␊ |
592 | }␊ |
593 | RECURSE_ENTRYTREE(findGroupScope,rootNav);␊ |
594 | }␊ |
595 | ␊ |
596 | static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)␊ |
597 | {␊ |
598 | if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())␊ |
599 | {␊ |
600 | rootNav->loadEntry(g_storage);␊ |
601 | Entry *root = rootNav->entry();␊ |
602 | ␊ |
603 | if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||␊ |
604 | (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))␊ |
605 | {␊ |
606 | GroupDef *gd;␊ |
607 | if ((gd=Doxygen::groupSDict->find(root->name)))␊ |
608 | {␊ |
609 | //printf("adding %s to group %s\n",root->name.data(),gd->name().data());␊ |
610 | addGroupToGroups(root,gd);␊ |
611 | }␊ |
612 | }␊ |
613 | ␊ |
614 | rootNav->releaseEntry();␊ |
615 | }␊ |
616 | if (rootNav->children())␊ |
617 | {␊ |
618 | EntryNavListIterator eli(*rootNav->children());␊ |
619 | EntryNav *e;␊ |
620 | for (;(e=eli.current());++eli)␊ |
621 | {␊ |
622 | organizeSubGroupsFiltered(e,additional);␊ |
623 | }␊ |
624 | }␊ |
625 | }␊ |
626 | ␊ |
627 | static void organizeSubGroups(EntryNav *rootNav)␊ |
628 | {␊ |
629 | //printf("Defining groups\n");␊ |
630 | // first process the @defgroups blocks␊ |
631 | organizeSubGroupsFiltered(rootNav,FALSE);␊ |
632 | //printf("Additional groups\n");␊ |
633 | // then process the @addtogroup, @weakgroup blocks␊ |
634 | organizeSubGroupsFiltered(rootNav,TRUE);␊ |
635 | }␊ |
636 | ␊ |
637 | //----------------------------------------------------------------------␊ |
638 | ␊ |
639 | static void buildFileList(EntryNav *rootNav)␊ |
640 | {␊ |
641 | if (((rootNav->section()==Entry::FILEDOC_SEC) ||␊ |
642 | ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&␊ |
643 | !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files␊ |
644 | )␊ |
645 | {␊ |
646 | rootNav->loadEntry(g_storage);␊ |
647 | Entry *root = rootNav->entry();␊ |
648 | ␊ |
649 | bool ambig;␊ |
650 | FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);␊ |
651 | //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);␊ |
652 | if (fd && !ambig)␊ |
653 | {␊ |
654 | #if 0␊ |
655 | if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||␊ |
656 | (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))␊ |
657 | {␊ |
658 | warn(␊ |
659 | root->fileName,root->startLine,␊ |
660 | "warning: file %s already documented. "␊ |
661 | "Skipping documentation.",␊ |
662 | root->name.data()␊ |
663 | );␊ |
664 | }␊ |
665 | else␊ |
666 | #endif␊ |
667 | {␊ |
668 | //printf("Adding documentation!\n");␊ |
669 | // using FALSE in setDocumentation is small hack to make sure a file ␊ |
670 | // is documented even if a \file command is used without further ␊ |
671 | // documentation␊ |
672 | fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);␊ |
673 | fd->setBriefDescription(root->brief,root->briefFile,root->briefLine); ␊ |
674 | fd->addSectionsToDefinition(root->anchors);␊ |
675 | fd->setRefItems(root->sli);␊ |
676 | QListIterator<Grouping> gli(*root->groups);␊ |
677 | Grouping *g;␊ |
678 | for (;(g=gli.current());++gli)␊ |
679 | {␊ |
680 | GroupDef *gd=0;␊ |
681 | if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))␊ |
682 | {␊ |
683 | gd->addFile(fd);␊ |
684 | fd->makePartOfGroup(gd);␊ |
685 | //printf("File %s: in group %s\n",fd->name().data(),s->data());␊ |
686 | }␊ |
687 | }␊ |
688 | }␊ |
689 | }␊ |
690 | else␊ |
691 | {␊ |
692 | const char *fn = root->fileName.data();␊ |
693 | QCString text;␊ |
694 | text.sprintf("warning: the name `%s' supplied as "␊ |
695 | "the second argument in the \\file statement ",␊ |
696 | qPrint(root->name)␊ |
697 | );␊ |
698 | if (ambig) // name is ambiguous␊ |
699 | {␊ |
700 | text+="matches the following input files:\n";␊ |
701 | text+=showFileDefMatches(Doxygen::inputNameDict,root->name);␊ |
702 | text+="Please use a more specific name by "␊ |
703 | "including a (larger) part of the path!";␊ |
704 | }␊ |
705 | else // name is not an input file␊ |
706 | {␊ |
707 | text+="is not an input file";␊ |
708 | }␊ |
709 | warn(fn,root->startLine,text);␊ |
710 | }␊ |
711 | ␊ |
712 | rootNav->releaseEntry();␊ |
713 | }␊ |
714 | RECURSE_ENTRYTREE(buildFileList,rootNav);␊ |
715 | }␊ |
716 | ␊ |
717 | static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)␊ |
718 | {␊ |
719 | if ( ␊ |
720 | (!root->doc.stripWhiteSpace().isEmpty() || ␊ |
721 | !root->brief.stripWhiteSpace().isEmpty() || ␊ |
722 | Config_getBool("EXTRACT_ALL")␊ |
723 | ) && root->protection!=Private␊ |
724 | )␊ |
725 | { ␊ |
726 | //printf(">>>>>> includeFile=%s\n",root->includeFile.data());␊ |
727 | ␊ |
728 | bool local=Config_getBool("FORCE_LOCAL_INCLUDES");␊ |
729 | QCString includeFile = root->includeFile;␊ |
730 | if (!includeFile.isEmpty() && includeFile.at(0)=='"')␊ |
731 | {␊ |
732 | local = TRUE;␊ |
733 | includeFile=includeFile.mid(1,includeFile.length()-2);␊ |
734 | }␊ |
735 | else if (!includeFile.isEmpty() && includeFile.at(0)=='<')␊ |
736 | {␊ |
737 | local = FALSE;␊ |
738 | includeFile=includeFile.mid(1,includeFile.length()-2);␊ |
739 | }␊ |
740 | ␊ |
741 | bool ambig;␊ |
742 | FileDef *fd=0;␊ |
743 | // see if we need to include a verbatim copy of the header file␊ |
744 | //printf("root->includeFile=%s\n",root->includeFile.data());␊ |
745 | if (!includeFile.isEmpty() && ␊ |
746 | (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0␊ |
747 | )␊ |
748 | { // explicit request␊ |
749 | QCString text;␊ |
750 | text.sprintf("warning: the name `%s' supplied as "␊ |
751 | "the argument of the \\class, \\struct, \\union, or \\include command ",␊ |
752 | qPrint(includeFile)␊ |
753 | );␊ |
754 | if (ambig) // name is ambiguous␊ |
755 | {␊ |
756 | text+="matches the following input files:\n";␊ |
757 | text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);␊ |
758 | text+="Please use a more specific name by "␊ |
759 | "including a (larger) part of the path!";␊ |
760 | }␊ |
761 | else // name is not an input file␊ |
762 | {␊ |
763 | text+="is not an input file";␊ |
764 | }␊ |
765 | warn(root->fileName,root->startLine,text);␊ |
766 | }␊ |
767 | else if (includeFile.isEmpty() && ifd &&␊ |
768 | // see if the file extension makes sense␊ |
769 | guessSection(ifd->name())==Entry::HEADER_SEC)␊ |
770 | { // implicit assumption␊ |
771 | fd=ifd;␊ |
772 | }␊ |
773 | ␊ |
774 | // if a file is found, we mark it as a source file.␊ |
775 | if (fd)␊ |
776 | {␊ |
777 | QCString iName = !root->includeName.isEmpty() ? ␊ |
778 | root->includeName : includeFile;␊ |
779 | if (!iName.isEmpty()) // user specified include file␊ |
780 | {␊ |
781 | if (iName.at(0)=='<') local=FALSE; // explicit override␊ |
782 | if (iName.at(0)=='"' || iName.at(0)=='<')␊ |
783 | {␊ |
784 | iName=iName.mid(1,iName.length()-2); // strip quotes or brackets␊ |
785 | }␊ |
786 | if (iName.isEmpty())␊ |
787 | {␊ |
788 | iName=fd->name();␊ |
789 | }␊ |
790 | }␊ |
791 | else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty()) ␊ |
792 | {␊ |
793 | iName=stripFromIncludePath(fd->absFilePath());␊ |
794 | }␊ |
795 | else // use name of the file containing the class definition␊ |
796 | {␊ |
797 | iName=fd->name();␊ |
798 | }␊ |
799 | if (fd->generateSourceFile()) // generate code for header␊ |
800 | {␊ |
801 | cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());␊ |
802 | }␊ |
803 | else // put #include in the class documentation without link␊ |
804 | {␊ |
805 | cd->setIncludeFile(0,iName,local,TRUE);␊ |
806 | }␊ |
807 | }␊ |
808 | }␊ |
809 | }␊ |
810 | ␊ |
811 | #if 0␊ |
812 | static bool addNamespace(Entry *root,ClassDef *cd)␊ |
813 | {␊ |
814 | // see if this class is defined inside a namespace␊ |
815 | if (root->section & Entry::COMPOUND_MASK)␊ |
816 | {␊ |
817 | Entry *e = root->parent;␊ |
818 | while (e)␊ |
819 | {␊ |
820 | if (e->section==Entry::NAMESPACE_SEC)␊ |
821 | {␊ |
822 | NamespaceDef *nd=0;␊ |
823 | QCString nsName = stripAnonymousNamespaceScope(e->name);␊ |
824 | //printf("addNameSpace() trying: %s\n",nsName.data());␊ |
825 | if (!nsName.isEmpty() && nsName.at(0)!='@' &&␊ |
826 | (nd=getResolvedNamespace(nsName))␊ |
827 | )␊ |
828 | {␊ |
829 | cd->setNamespace(nd);␊ |
830 | cd->setOuterScope(nd);␊ |
831 | nd->insertClass(cd);␊ |
832 | return TRUE;␊ |
833 | }␊ |
834 | }␊ |
835 | e=e->parent;␊ |
836 | } ␊ |
837 | }␊ |
838 | return FALSE;␊ |
839 | }␊ |
840 | #endif␊ |
841 | ␊ |
842 | #if 0␊ |
843 | static Definition *findScope(Entry *root,int level=0)␊ |
844 | {␊ |
845 | if (root==0) return 0;␊ |
846 | //printf("start findScope name=%s\n",root->name.data());␊ |
847 | Definition *result=0;␊ |
848 | if (root->section&Entry::SCOPE_MASK)␊ |
849 | {␊ |
850 | result = findScope(root->parent,level+1); // traverse to the root of the tree␊ |
851 | if (result)␊ |
852 | {␊ |
853 | //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);␊ |
854 | // TODO: look at template arguments␊ |
855 | result = result->findInnerCompound(root->name);␊ |
856 | }␊ |
857 | else // reached the global scope␊ |
858 | {␊ |
859 | // TODO: look at template arguments␊ |
860 | result = Doxygen::globalScope->findInnerCompound(root->name);␊ |
861 | //printf("Found in globalScope %s at level %d\n",result->name().data(),level);␊ |
862 | }␊ |
863 | }␊ |
864 | //printf("end findScope(%s,%d)=%s\n",root->name.data(),␊ |
865 | // level,result==0 ? "<none>" : result->name().data());␊ |
866 | return result;␊ |
867 | }␊ |
868 | #endif␊ |
869 | ␊ |
870 | /*! returns the Definition object belonging to the first \a level levels of ␊ |
871 | * full qualified name \a name. Creates an artificial scope if the scope is␊ |
872 | * not found and set the parent/child scope relation if the scope is found.␊ |
873 | */␊ |
874 | static Definition *buildScopeFromQualifiedName(const QCString name,int level)␊ |
875 | {␊ |
876 | int i=0;␊ |
877 | int p=0,l;␊ |
878 | Definition *prevScope=Doxygen::globalScope;␊ |
879 | QCString fullScope;␊ |
880 | while (i<level)␊ |
881 | {␊ |
882 | int idx=getScopeFragment(name,p,&l);␊ |
883 | QCString nsName = name.mid(idx,l);␊ |
884 | if (nsName.isEmpty()) return prevScope;␊ |
885 | if (!fullScope.isEmpty()) fullScope+="::";␊ |
886 | fullScope+=nsName;␊ |
887 | NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);␊ |
888 | Definition *innerScope = nd;␊ |
889 | ClassDef *cd=0; ␊ |
890 | if (nd==0) cd = getClass(fullScope);␊ |
891 | if (nd==0 && cd) // scope is a class␊ |
892 | {␊ |
893 | innerScope = cd;␊ |
894 | }␊ |
895 | else if (nd==0 && cd==0) // scope is not known!␊ |
896 | {␊ |
897 | // introduce bogus namespace␊ |
898 | //printf("++ adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data());␊ |
899 | nd=new NamespaceDef(␊ |
900 | "[generated]",1,fullScope);␊ |
901 | ␊ |
902 | // add namespace to the list␊ |
903 | Doxygen::namespaceSDict->inSort(fullScope,nd);␊ |
904 | innerScope = nd;␊ |
905 | }␊ |
906 | else // scope is a namespace␊ |
907 | {␊ |
908 | }␊ |
909 | // make the parent/child scope relation␊ |
910 | prevScope->addInnerCompound(innerScope);␊ |
911 | innerScope->setOuterScope(prevScope);␊ |
912 | // proceed to the next scope fragment␊ |
913 | p=idx+l+2;␊ |
914 | prevScope=innerScope;␊ |
915 | i++;␊ |
916 | }␊ |
917 | return prevScope;␊ |
918 | }␊ |
919 | ␊ |
920 | static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,␊ |
921 | FileDef *fileScope)␊ |
922 | {␊ |
923 | //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());␊ |
924 | Definition *resultScope=startScope;␊ |
925 | if (resultScope==0) resultScope=Doxygen::globalScope;␊ |
926 | QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);␊ |
927 | int l1=0,i1;␊ |
928 | i1=getScopeFragment(scope,0,&l1);␊ |
929 | if (i1==-1) ␊ |
930 | {␊ |
931 | //printf(">no fragments!\n");␊ |
932 | return resultScope;␊ |
933 | }␊ |
934 | int p=i1+l1,l2=0,i2;␊ |
935 | while ((i2=getScopeFragment(scope,p,&l2))!=-1)␊ |
936 | {␊ |
937 | QCString nestedNameSpecifier = scope.mid(i1,l1);␊ |
938 | Definition *orgScope = resultScope;␊ |
939 | //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());␊ |
940 | resultScope = resultScope->findInnerCompound(nestedNameSpecifier);␊ |
941 | //printf(" resultScope=%p\n",resultScope);␊ |
942 | if (resultScope==0) ␊ |
943 | {␊ |
944 | NamespaceSDict *usedNamespaces;␊ |
945 | if (orgScope==Doxygen::globalScope && fileScope &&␊ |
946 | (usedNamespaces = fileScope->getUsedNamespaces())) ␊ |
947 | // also search for used namespaces ␊ |
948 | {␊ |
949 | NamespaceSDict::Iterator ni(*usedNamespaces);␊ |
950 | NamespaceDef *nd;␊ |
951 | for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)␊ |
952 | {␊ |
953 | // restart search within the used namespace␊ |
954 | resultScope = findScopeFromQualifiedName(nd,n,fileScope);␊ |
955 | }␊ |
956 | if (resultScope) ␊ |
957 | {␊ |
958 | // for a nested class A::I in used namespace N, we get␊ |
959 | // N::A::I while looking for A, so we should compare␊ |
960 | // resultScope->name() against scope.left(i2+l2)␊ |
961 | //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());␊ |
962 | if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))␊ |
963 | {␊ |
964 | break;␊ |
965 | }␊ |
966 | goto nextFragment;␊ |
967 | }␊ |
968 | }␊ |
969 | ␊ |
970 | // also search for used classes. Complication: we haven't been able ␊ |
971 | // to put them in the right scope yet, because we are still resolving␊ |
972 | // the scope relations!␊ |
973 | // Therefore loop through all used classes and see if there is a right ␊ |
974 | // scope match between the used class and nestedNameSpecifier.␊ |
975 | QDictIterator<FileDef> ui(g_usingDeclarations);␊ |
976 | FileDef *usedFd;␊ |
977 | for (ui.toFirst();(usedFd=ui.current());++ui)␊ |
978 | {␊ |
979 | //printf("Checking using class %s\n",ui.currentKey());␊ |
980 | if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))␊ |
981 | {␊ |
982 | // ui.currentKey() is the fully qualified name of nestedNameSpecifier␊ |
983 | // so use this instead.␊ |
984 | QCString fqn = QCString(ui.currentKey())+␊ |
985 | scope.right(scope.length()-p);␊ |
986 | resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"));␊ |
987 | //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);␊ |
988 | if (resultScope) ␊ |
989 | {␊ |
990 | //printf("> Match! resultScope=%s\n",resultScope->name().data());␊ |
991 | return resultScope;␊ |
992 | }␊ |
993 | }␊ |
994 | }␊ |
995 | ␊ |
996 | //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());␊ |
997 | return 0;␊ |
998 | }␊ |
999 | nextFragment:␊ |
1000 | i1=i2;␊ |
1001 | l1=l2;␊ |
1002 | p=i2+l2;␊ |
1003 | }␊ |
1004 | //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());␊ |
1005 | return resultScope;␊ |
1006 | }␊ |
1007 | ␊ |
1008 | ArgumentList *getTemplateArgumentsFromName(␊ |
1009 | const QCString &name,␊ |
1010 | const QList<ArgumentList> *tArgLists)␊ |
1011 | {␊ |
1012 | if (tArgLists==0) return 0;␊ |
1013 | ␊ |
1014 | QListIterator<ArgumentList> ali(*tArgLists);␊ |
1015 | // for each scope fragment, check if it is a template and advance through␊ |
1016 | // the list if so.␊ |
1017 | int i,p=0;␊ |
1018 | while ((i=name.find("::",p))!=-1)␊ |
1019 | {␊ |
1020 | NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));␊ |
1021 | if (nd==0)␊ |
1022 | {␊ |
1023 | ClassDef *cd = getClass(name.left(i));␊ |
1024 | if (cd)␊ |
1025 | {␊ |
1026 | if (cd->templateArguments())␊ |
1027 | {␊ |
1028 | ++ali;␊ |
1029 | }␊ |
1030 | }␊ |
1031 | }␊ |
1032 | p=i+2;␊ |
1033 | }␊ |
1034 | return ali.current();␊ |
1035 | }␊ |
1036 | ␊ |
1037 | static ClassDef::CompoundType convertToCompoundType(int section,int specifier)␊ |
1038 | {␊ |
1039 | ClassDef::CompoundType sec=ClassDef::Class; ␊ |
1040 | if (specifier&Entry::Struct) ␊ |
1041 | sec=ClassDef::Struct;␊ |
1042 | else if (specifier&Entry::Union) ␊ |
1043 | sec=ClassDef::Union;␊ |
1044 | else if (specifier&Entry::Interface) ␊ |
1045 | sec=ClassDef::Interface;␊ |
1046 | else if (specifier&Entry::Protocol) ␊ |
1047 | sec=ClassDef::Protocol;␊ |
1048 | else if (specifier&Entry::Category) ␊ |
1049 | sec=ClassDef::Category;␊ |
1050 | else if (specifier&Entry::Exception) ␊ |
1051 | sec=ClassDef::Exception;␊ |
1052 | ␊ |
1053 | switch(section)␊ |
1054 | {␊ |
1055 | //case Entry::UNION_SEC: ␊ |
1056 | case Entry::UNIONDOC_SEC: ␊ |
1057 | sec=ClassDef::Union; ␊ |
1058 | break;␊ |
1059 | //case Entry::STRUCT_SEC:␊ |
1060 | case Entry::STRUCTDOC_SEC: ␊ |
1061 | sec=ClassDef::Struct; ␊ |
1062 | break;␊ |
1063 | //case Entry::INTERFACE_SEC:␊ |
1064 | case Entry::INTERFACEDOC_SEC:␊ |
1065 | sec=ClassDef::Interface; ␊ |
1066 | break;␊ |
1067 | //case Entry::PROTOCOL_SEC:␊ |
1068 | case Entry::PROTOCOLDOC_SEC:␊ |
1069 | sec=ClassDef::Protocol; ␊ |
1070 | break;␊ |
1071 | //case Entry::CATEGORY_SEC:␊ |
1072 | case Entry::CATEGORYDOC_SEC:␊ |
1073 | sec=ClassDef::Category; ␊ |
1074 | break;␊ |
1075 | //case Entry::EXCEPTION_SEC:␊ |
1076 | case Entry::EXCEPTIONDOC_SEC:␊ |
1077 | sec=ClassDef::Exception; ␊ |
1078 | break;␊ |
1079 | }␊ |
1080 | return sec;␊ |
1081 | }␊ |
1082 | ␊ |
1083 | ␊ |
1084 | static void addClassToContext(EntryNav *rootNav)␊ |
1085 | {␊ |
1086 | //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());␊ |
1087 | rootNav->loadEntry(g_storage);␊ |
1088 | Entry *root = rootNav->entry();␊ |
1089 | ␊ |
1090 | //NamespaceDef *nd = 0;␊ |
1091 | FileDef *fd = rootNav->fileDef();␊ |
1092 | ␊ |
1093 | QCString scName;␊ |
1094 | if (rootNav->parent()->section()&Entry::SCOPE_MASK)␊ |
1095 | {␊ |
1096 | scName=rootNav->parent()->name();␊ |
1097 | }␊ |
1098 | // name without parent's scope␊ |
1099 | QCString fullName = root->name;␊ |
1100 | ␊ |
1101 | // strip off any template parameters (but not those for specializations)␊ |
1102 | fullName=stripTemplateSpecifiersFromScope(fullName);␊ |
1103 | ␊ |
1104 | // name with scope (if not present already)␊ |
1105 | QCString qualifiedName = fullName;␊ |
1106 | if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))␊ |
1107 | {␊ |
1108 | qualifiedName.prepend(scName+"::");␊ |
1109 | }␊ |
1110 | ␊ |
1111 | // see if we already found the class before␊ |
1112 | ClassDef *cd = getClass(qualifiedName);␊ |
1113 | ␊ |
1114 | Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",␊ |
1115 | cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);␊ |
1116 | ␊ |
1117 | if (cd) ␊ |
1118 | {␊ |
1119 | fullName=cd->name();␊ |
1120 | Debug::print(Debug::Classes,0," Existing class %s!\n",cd->name().data());␊ |
1121 | //if (cd->templateArguments()==0)␊ |
1122 | //{␊ |
1123 | // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());␊ |
1124 | // cd->setTemplateArguments(tArgList);␊ |
1125 | //}␊ |
1126 | ␊ |
1127 | cd->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
1128 | cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1129 | ␊ |
1130 | if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)␊ |
1131 | {␊ |
1132 | cd->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
1133 | cd->setBodyDef(fd);␊ |
1134 | }␊ |
1135 | //cd->setName(fullName); // change name to match docs␊ |
1136 | ␊ |
1137 | if (cd->templateArguments()==0) ␊ |
1138 | {␊ |
1139 | // this happens if a template class declared with @class is found␊ |
1140 | // before the actual definition.␊ |
1141 | ArgumentList *tArgList = ␊ |
1142 | getTemplateArgumentsFromName(cd->name(),root->tArgLists);␊ |
1143 | cd->setTemplateArguments(tArgList);␊ |
1144 | }␊ |
1145 | ␊ |
1146 | cd->setCompoundType(convertToCompoundType(root->section,root->spec));␊ |
1147 | }␊ |
1148 | else // new class␊ |
1149 | {␊ |
1150 | ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);␊ |
1151 | ␊ |
1152 | QCString className;␊ |
1153 | QCString namespaceName;␊ |
1154 | extractNamespaceName(fullName,className,namespaceName);␊ |
1155 | ␊ |
1156 | //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",␊ |
1157 | // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());␊ |
1158 | ␊ |
1159 | QCString tagName;␊ |
1160 | QCString refFileName;␊ |
1161 | if (rootNav->tagInfo())␊ |
1162 | {␊ |
1163 | tagName = rootNav->tagInfo()->tagName;␊ |
1164 | refFileName = rootNav->tagInfo()->fileName;␊ |
1165 | }␊ |
1166 | cd=new ClassDef(root->fileName,root->startLine,fullName,sec,␊ |
1167 | tagName,refFileName);␊ |
1168 | Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d\n",␊ |
1169 | fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);␊ |
1170 | cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition␊ |
1171 | cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1172 | cd->setLanguage(root->lang);␊ |
1173 | cd->setHidden(root->hidden);␊ |
1174 | cd->setArtificial(root->artificial);␊ |
1175 | cd->setTypeConstraints(root->typeConstr);␊ |
1176 | //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());␊ |
1177 | ␊ |
1178 | ArgumentList *tArgList = ␊ |
1179 | getTemplateArgumentsFromName(fullName,root->tArgLists);␊ |
1180 | //printf("class %s template args=%s\n",fullName.data(),␊ |
1181 | // tArgList ? tempArgListToString(tArgList).data() : "<none>");␊ |
1182 | cd->setTemplateArguments(tArgList);␊ |
1183 | cd->setProtection(root->protection);␊ |
1184 | cd->setIsStatic(root->stat);␊ |
1185 | ␊ |
1186 | // file definition containing the class cd␊ |
1187 | cd->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
1188 | cd->setBodyDef(fd);␊ |
1189 | ␊ |
1190 | // see if the class is found inside a namespace ␊ |
1191 | //bool found=addNamespace(root,cd);␊ |
1192 | ␊ |
1193 | ␊ |
1194 | // the empty string test is needed for extract all case␊ |
1195 | cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1196 | cd->insertUsedFile(root->fileName);␊ |
1197 | ␊ |
1198 | // add class to the list␊ |
1199 | //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());␊ |
1200 | Doxygen::classSDict->append(fullName,cd);␊ |
1201 | ␊ |
1202 | }␊ |
1203 | ␊ |
1204 | cd->addSectionsToDefinition(root->anchors);␊ |
1205 | if (!root->subGrouping) cd->setSubGrouping(FALSE);␊ |
1206 | if (cd->hasDocumentation())␊ |
1207 | {␊ |
1208 | addIncludeFile(cd,fd,root);␊ |
1209 | }␊ |
1210 | if (fd && (root->section & Entry::COMPOUND_MASK)) ␊ |
1211 | {␊ |
1212 | //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",␊ |
1213 | // cd->name().data(),␊ |
1214 | // fd->name().data(),␊ |
1215 | // root->fileName.data()␊ |
1216 | // );␊ |
1217 | cd->setFileDef(fd);␊ |
1218 | fd->insertClass(cd);␊ |
1219 | }␊ |
1220 | addClassToGroups(root,cd);␊ |
1221 | cd->setRefItems(root->sli);␊ |
1222 | ␊ |
1223 | rootNav->releaseEntry();␊ |
1224 | }␊ |
1225 | ␊ |
1226 | //----------------------------------------------------------------------␊ |
1227 | // build a list of all classes mentioned in the documentation␊ |
1228 | // and all classes that have a documentation block before their definition.␊ |
1229 | static void buildClassList(EntryNav *rootNav)␊ |
1230 | {␊ |
1231 | if (␊ |
1232 | ((rootNav->section() & Entry::COMPOUND_MASK) || ␊ |
1233 | rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()␊ |
1234 | )␊ |
1235 | {␊ |
1236 | addClassToContext(rootNav);␊ |
1237 | }␊ |
1238 | RECURSE_ENTRYTREE(buildClassList,rootNav);␊ |
1239 | }␊ |
1240 | ␊ |
1241 | static void buildClassDocList(EntryNav *rootNav)␊ |
1242 | {␊ |
1243 | if (␊ |
1244 | (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()␊ |
1245 | )␊ |
1246 | {␊ |
1247 | addClassToContext(rootNav);␊ |
1248 | }␊ |
1249 | RECURSE_ENTRYTREE(buildClassDocList,rootNav);␊ |
1250 | }␊ |
1251 | ␊ |
1252 | static void resolveClassNestingRelations()␊ |
1253 | {␊ |
1254 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
1255 | for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;␊ |
1256 | ␊ |
1257 | bool done=FALSE;␊ |
1258 | int iteration=0;␊ |
1259 | while (!done)␊ |
1260 | {␊ |
1261 | done=TRUE;␊ |
1262 | ++iteration;␊ |
1263 | ClassDef *cd=0;␊ |
1264 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
1265 | {␊ |
1266 | if (!cd->visited)␊ |
1267 | {␊ |
1268 | QCString name = stripAnonymousNamespaceScope(cd->name());␊ |
1269 | //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);␊ |
1270 | // also add class to the correct structural context ␊ |
1271 | Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,␊ |
1272 | name,cd->getFileDef());␊ |
1273 | if (d)␊ |
1274 | {␊ |
1275 | //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);␊ |
1276 | d->addInnerCompound(cd);␊ |
1277 | cd->setOuterScope(d);␊ |
1278 | cd->visited=TRUE;␊ |
1279 | done=FALSE;␊ |
1280 | }␊ |
1281 | //else␊ |
1282 | //{␊ |
1283 | // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);␊ |
1284 | //}␊ |
1285 | }␊ |
1286 | }␊ |
1287 | }␊ |
1288 | ␊ |
1289 | //give warnings for unresolved compounds␊ |
1290 | ClassDef *cd=0;␊ |
1291 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
1292 | {␊ |
1293 | if (!cd->visited)␊ |
1294 | {␊ |
1295 | QCString name = stripAnonymousNamespaceScope(cd->name());␊ |
1296 | //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);␊ |
1297 | /// create the scope artificially␊ |
1298 | // anyway, so we can at least relate scopes properly.␊ |
1299 | Definition *d = buildScopeFromQualifiedName(name,name.contains("::"));␊ |
1300 | if (d!=cd && !cd->getDefFileName().isEmpty()) ␊ |
1301 | // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }␊ |
1302 | // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!␊ |
1303 | // also avoid warning for stuff imported via a tagfile.␊ |
1304 | {␊ |
1305 | d->addInnerCompound(cd);␊ |
1306 | cd->setOuterScope(d);␊ |
1307 | warn(cd->getDefFileName(),cd->getDefLine(),␊ |
1308 | "warning: Internal inconsistency: scope for class %s not "␊ |
1309 | "found!",name.data()␊ |
1310 | );␊ |
1311 | }␊ |
1312 | }␊ |
1313 | }␊ |
1314 | }␊ |
1315 | ␊ |
1316 | void distributeClassGroupRelations()␊ |
1317 | {␊ |
1318 | static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES");␊ |
1319 | if (!inlineGroupedClasses) return;␊ |
1320 | //printf("** distributeClassGroupRelations()\n");␊ |
1321 | ␊ |
1322 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
1323 | for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;␊ |
1324 | ␊ |
1325 | ClassDef *cd;␊ |
1326 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
1327 | {␊ |
1328 | //printf("Checking %s\n",cd->name().data());␊ |
1329 | // distribute the group to nested classes as well␊ |
1330 | if (!cd->visited && cd->partOfGroups()!=0 && cd->getInnerClasses())␊ |
1331 | {␊ |
1332 | //printf(" Candidate for merging\n");␊ |
1333 | ClassSDict::Iterator ncli(*cd->getInnerClasses());␊ |
1334 | ClassDef *ncd;␊ |
1335 | GroupDef *gd = cd->partOfGroups()->at(0);␊ |
1336 | for (ncli.toFirst();(ncd=ncli.current());++ncli)␊ |
1337 | {␊ |
1338 | if (ncd->partOfGroups()==0)␊ |
1339 | {␊ |
1340 | //printf(" Adding %s to group '%s'\n",ncd->name().data(),␊ |
1341 | // gd->groupTitle());␊ |
1342 | ncd->makePartOfGroup(gd);␊ |
1343 | gd->addClass(ncd);␊ |
1344 | }␊ |
1345 | }␊ |
1346 | cd->visited=TRUE; // only visit every class once␊ |
1347 | }␊ |
1348 | }␊ |
1349 | }␊ |
1350 | ␊ |
1351 | //----------------------------------------------------------------------␊ |
1352 | // build a list of all namespaces mentioned in the documentation␊ |
1353 | // and all namespaces that have a documentation block before their definition.␊ |
1354 | static void buildNamespaceList(EntryNav *rootNav)␊ |
1355 | {␊ |
1356 | if (␊ |
1357 | (rootNav->section()==Entry::NAMESPACE_SEC ||␊ |
1358 | rootNav->section()==Entry::NAMESPACEDOC_SEC ||␊ |
1359 | rootNav->section()==Entry::PACKAGEDOC_SEC␊ |
1360 | ) && ␊ |
1361 | !rootNav->name().isEmpty()␊ |
1362 | )␊ |
1363 | {␊ |
1364 | rootNav->loadEntry(g_storage);␊ |
1365 | Entry *root = rootNav->entry();␊ |
1366 | ␊ |
1367 | //printf("** buildNamespaceList(%s)\n",root->name.data());␊ |
1368 | ␊ |
1369 | QCString fName = root->name;␊ |
1370 | if (root->section==Entry::PACKAGEDOC_SEC)␊ |
1371 | {␊ |
1372 | fName=substitute(fName,".","::");␊ |
1373 | }␊ |
1374 | ␊ |
1375 | QCString fullName = stripAnonymousNamespaceScope(fName);␊ |
1376 | if (!fullName.isEmpty())␊ |
1377 | {␊ |
1378 | //printf("Found namespace %s in %s at line %d\n",root->name.data(),␊ |
1379 | // root->fileName.data(), root->startLine);␊ |
1380 | NamespaceDef *nd;␊ |
1381 | if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace␊ |
1382 | {␊ |
1383 | #if 0␊ |
1384 | if (!root->doc.isEmpty() || !root->brief.isEmpty()) // block contains docs␊ |
1385 | { ␊ |
1386 | if (nd->documentation().isEmpty() && !root->doc.isEmpty())␊ |
1387 | {␊ |
1388 | #endif␊ |
1389 | nd->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
1390 | nd->setName(fullName); // change name to match docs␊ |
1391 | nd->addSectionsToDefinition(root->anchors);␊ |
1392 | #if 0␊ |
1393 | }␊ |
1394 | else if (!nd->documentation().isEmpty() && !root->doc.isEmpty())␊ |
1395 | {␊ |
1396 | warn(␊ |
1397 | root->fileName,root->startLine,␊ |
1398 | "warning: namespace %s already has a detailed description found in file %s at line %d. "␊ |
1399 | "Skipping the documentation found here.",␊ |
1400 | fullName.data(),nd->docFile().data(),nd->docLine());␊ |
1401 | }␊ |
1402 | if (nd->briefDescription().isEmpty() && !root->brief.isEmpty())␊ |
1403 | {␊ |
1404 | #endif␊ |
1405 | nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1406 | #if 0␊ |
1407 | nd->setName(fullName); // change name to match docs␊ |
1408 | }␊ |
1409 | else if (!nd->briefDescription().isEmpty() && !root->brief.isEmpty())␊ |
1410 | {␊ |
1411 | warn(root->fileName,root->startLine,␊ |
1412 | "warning: namespace %s already has a brief description found in file %s at line %d. "␊ |
1413 | "Skipping the documentation found here.",␊ |
1414 | fullName.data(),nd->docFile().data(),nd->docLine()␊ |
1415 | );␊ |
1416 | }␊ |
1417 | }␊ |
1418 | #endif␊ |
1419 | ␊ |
1420 | // file definition containing the namespace nd␊ |
1421 | FileDef *fd=rootNav->fileDef();␊ |
1422 | // insert the namespace in the file definition␊ |
1423 | if (fd) fd->insertNamespace(nd);␊ |
1424 | addNamespaceToGroups(root,nd);␊ |
1425 | nd->setRefItems(root->sli);␊ |
1426 | }␊ |
1427 | else // fresh namespace␊ |
1428 | {␊ |
1429 | QCString tagName;␊ |
1430 | QCString tagFileName;␊ |
1431 | if (rootNav->tagInfo())␊ |
1432 | {␊ |
1433 | tagName=rootNav->tagInfo()->tagName;␊ |
1434 | tagFileName=rootNav->tagInfo()->fileName;␊ |
1435 | }␊ |
1436 | //printf("++ new namespace %s\n",fullName.data());␊ |
1437 | NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName);␊ |
1438 | nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition␊ |
1439 | nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1440 | nd->addSectionsToDefinition(root->anchors);␊ |
1441 | nd->setHidden(root->hidden);␊ |
1442 | nd->setArtificial(root->artificial);␊ |
1443 | ␊ |
1444 | //printf("Adding namespace to group\n");␊ |
1445 | addNamespaceToGroups(root,nd);␊ |
1446 | nd->setRefItems(root->sli);␊ |
1447 | ␊ |
1448 | // file definition containing the namespace nd␊ |
1449 | FileDef *fd=rootNav->fileDef();␊ |
1450 | // insert the namespace in the file definition␊ |
1451 | if (fd) fd->insertNamespace(nd);␊ |
1452 | ␊ |
1453 | // the empty string test is needed for extract all case␊ |
1454 | nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1455 | nd->insertUsedFile(root->fileName);␊ |
1456 | nd->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
1457 | nd->setBodyDef(fd);␊ |
1458 | // add class to the list␊ |
1459 | Doxygen::namespaceSDict->inSort(fullName,nd);␊ |
1460 | ␊ |
1461 | // also add namespace to the correct structural context ␊ |
1462 | Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName);␊ |
1463 | //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");␊ |
1464 | if (d==0) // we didn't find anything, create the scope artificially␊ |
1465 | // anyway, so we can at least relate scopes properly.␊ |
1466 | {␊ |
1467 | Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"));␊ |
1468 | d->addInnerCompound(nd);␊ |
1469 | nd->setOuterScope(d);␊ |
1470 | // TODO: Due to the order in which the tag file is written␊ |
1471 | // a nested class can be found before its parent!␊ |
1472 | }␊ |
1473 | else␊ |
1474 | {␊ |
1475 | d->addInnerCompound(nd);␊ |
1476 | nd->setOuterScope(d);␊ |
1477 | }␊ |
1478 | }␊ |
1479 | }␊ |
1480 | ␊ |
1481 | rootNav->releaseEntry();␊ |
1482 | }␊ |
1483 | RECURSE_ENTRYTREE(buildNamespaceList,rootNav);␊ |
1484 | }␊ |
1485 | ␊ |
1486 | //----------------------------------------------------------------------␊ |
1487 | ␊ |
1488 | static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,␊ |
1489 | const QCString &name)␊ |
1490 | {␊ |
1491 | NamespaceDef *usingNd =0;␊ |
1492 | if (unl)␊ |
1493 | {␊ |
1494 | //printf("Found namespace dict %d\n",unl->count());␊ |
1495 | NamespaceSDict::Iterator unli(*unl);␊ |
1496 | NamespaceDef *und;␊ |
1497 | for (unli.toFirst();(und=unli.current());++unli)␊ |
1498 | {␊ |
1499 | QCString uScope=und->name()+"::";␊ |
1500 | usingNd = getResolvedNamespace(uScope+name);␊ |
1501 | //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);␊ |
1502 | }␊ |
1503 | }␊ |
1504 | return usingNd;␊ |
1505 | }␊ |
1506 | ␊ |
1507 | static void findUsingDirectives(EntryNav *rootNav)␊ |
1508 | {␊ |
1509 | if (rootNav->section()==Entry::USINGDIR_SEC)␊ |
1510 | {␊ |
1511 | rootNav->loadEntry(g_storage);␊ |
1512 | Entry *root = rootNav->entry();␊ |
1513 | ␊ |
1514 | //printf("Found using directive %s at line %d of %s\n",␊ |
1515 | // root->name.data(),root->startLine,root->fileName.data());␊ |
1516 | QCString name=substitute(root->name,".","::");␊ |
1517 | if (!name.isEmpty())␊ |
1518 | {␊ |
1519 | NamespaceDef *usingNd = 0;␊ |
1520 | NamespaceDef *nd = 0;␊ |
1521 | FileDef *fd = rootNav->fileDef();␊ |
1522 | QCString nsName;␊ |
1523 | ␊ |
1524 | // see if the using statement was found inside a namespace or inside␊ |
1525 | // the global file scope.␊ |
1526 | if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&␊ |
1527 | (fd==0 || !fd->isJava()) // not a .java file␊ |
1528 | )␊ |
1529 | {␊ |
1530 | nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());␊ |
1531 | if (!nsName.isEmpty())␊ |
1532 | {␊ |
1533 | nd = getResolvedNamespace(nsName);␊ |
1534 | }␊ |
1535 | }␊ |
1536 | ␊ |
1537 | // find the scope in which the `using' namespace is defined by prepending␊ |
1538 | // the possible scopes in which the using statement was found, starting␊ |
1539 | // with the most inner scope and going to the most outer scope (i.e. ␊ |
1540 | // file scope). ␊ |
1541 | int scopeOffset = nsName.length();␊ |
1542 | do␊ |
1543 | {␊ |
1544 | QCString scope=scopeOffset>0 ? ␊ |
1545 | nsName.left(scopeOffset)+"::" : QCString();␊ |
1546 | usingNd = getResolvedNamespace(scope+name);␊ |
1547 | //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);␊ |
1548 | if (scopeOffset==0)␊ |
1549 | {␊ |
1550 | scopeOffset=-1;␊ |
1551 | }␊ |
1552 | else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)␊ |
1553 | {␊ |
1554 | scopeOffset=0;␊ |
1555 | }␊ |
1556 | } while (scopeOffset>=0 && usingNd==0);␊ |
1557 | ␊ |
1558 | if (usingNd==0 && nd) // not found, try used namespaces in this scope␊ |
1559 | // or in one of the parent namespace scopes␊ |
1560 | {␊ |
1561 | NamespaceDef *pnd = nd;␊ |
1562 | while (pnd && usingNd==0)␊ |
1563 | {␊ |
1564 | // also try with one of the used namespaces found earlier␊ |
1565 | usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);␊ |
1566 | ␊ |
1567 | // goto the parent␊ |
1568 | Definition *s = pnd->getOuterScope();␊ |
1569 | if (s && s->definitionType()==Definition::TypeNamespace)␊ |
1570 | {␊ |
1571 | pnd = (NamespaceDef*)s;␊ |
1572 | }␊ |
1573 | else␊ |
1574 | {␊ |
1575 | pnd = 0;␊ |
1576 | }␊ |
1577 | }␊ |
1578 | }␊ |
1579 | if (usingNd==0 && fd) // still nothing, also try used namespace in the␊ |
1580 | // global scope␊ |
1581 | {␊ |
1582 | usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);␊ |
1583 | }␊ |
1584 | ␊ |
1585 | //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");␊ |
1586 | ␊ |
1587 | // add the namespace the correct scope␊ |
1588 | if (usingNd)␊ |
1589 | {␊ |
1590 | //printf("using fd=%p nd=%p\n",fd,nd);␊ |
1591 | if (nd)␊ |
1592 | {␊ |
1593 | //printf("Inside namespace %s\n",nd->name().data());␊ |
1594 | nd->addUsingDirective(usingNd);␊ |
1595 | }␊ |
1596 | else if (fd)␊ |
1597 | {␊ |
1598 | //printf("Inside file %s\n",fd->name().data());␊ |
1599 | fd->addUsingDirective(usingNd);␊ |
1600 | }␊ |
1601 | }␊ |
1602 | else // unknown namespace, but add it anyway.␊ |
1603 | {␊ |
1604 | //printf("++ new unknown namespace %s\n",name.data());␊ |
1605 | NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name);␊ |
1606 | nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition␊ |
1607 | nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1608 | nd->addSectionsToDefinition(root->anchors);␊ |
1609 | //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);␊ |
1610 | nd->setHidden(root->hidden);␊ |
1611 | nd->setArtificial(TRUE);␊ |
1612 | ␊ |
1613 | QListIterator<Grouping> gli(*root->groups);␊ |
1614 | Grouping *g;␊ |
1615 | for (;(g=gli.current());++gli)␊ |
1616 | {␊ |
1617 | GroupDef *gd=0;␊ |
1618 | if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))␊ |
1619 | gd->addNamespace(nd);␊ |
1620 | }␊ |
1621 | ␊ |
1622 | // insert the namespace in the file definition␊ |
1623 | if (fd) ␊ |
1624 | {␊ |
1625 | fd->insertNamespace(nd);␊ |
1626 | fd->addUsingDirective(nd);␊ |
1627 | }␊ |
1628 | ␊ |
1629 | // the empty string test is needed for extract all case␊ |
1630 | nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1631 | nd->insertUsedFile(root->fileName);␊ |
1632 | // add class to the list␊ |
1633 | Doxygen::namespaceSDict->inSort(name,nd);␊ |
1634 | nd->setRefItems(root->sli);␊ |
1635 | }␊ |
1636 | }␊ |
1637 | ␊ |
1638 | rootNav->releaseEntry();␊ |
1639 | }␊ |
1640 | RECURSE_ENTRYTREE(findUsingDirectives,rootNav);␊ |
1641 | }␊ |
1642 | ␊ |
1643 | //----------------------------------------------------------------------␊ |
1644 | ␊ |
1645 | static void buildListOfUsingDecls(EntryNav *rootNav)␊ |
1646 | {␊ |
1647 | if (rootNav->section()==Entry::USINGDECL_SEC &&␊ |
1648 | !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member␊ |
1649 | )␊ |
1650 | {␊ |
1651 | rootNav->loadEntry(g_storage);␊ |
1652 | Entry *root = rootNav->entry();␊ |
1653 | ␊ |
1654 | QCString name = substitute(root->name,".","::");␊ |
1655 | if (g_usingDeclarations.find(name)==0)␊ |
1656 | {␊ |
1657 | FileDef *fd = rootNav->fileDef();␊ |
1658 | if (fd)␊ |
1659 | {␊ |
1660 | g_usingDeclarations.insert(name,fd);␊ |
1661 | }␊ |
1662 | }␊ |
1663 | ␊ |
1664 | rootNav->releaseEntry();␊ |
1665 | }␊ |
1666 | RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);␊ |
1667 | }␊ |
1668 | ␊ |
1669 | ␊ |
1670 | static void findUsingDeclarations(EntryNav *rootNav)␊ |
1671 | {␊ |
1672 | if (rootNav->section()==Entry::USINGDECL_SEC &&␊ |
1673 | !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member␊ |
1674 | )␊ |
1675 | {␊ |
1676 | rootNav->loadEntry(g_storage);␊ |
1677 | Entry *root = rootNav->entry();␊ |
1678 | ␊ |
1679 | //printf("Found using declaration %s at line %d of %s inside section %x\n",␊ |
1680 | // root->name.data(),root->startLine,root->fileName.data(),␊ |
1681 | // rootNav->parent()->section());␊ |
1682 | if (!root->name.isEmpty())␊ |
1683 | {␊ |
1684 | ClassDef *usingCd = 0;␊ |
1685 | NamespaceDef *nd = 0;␊ |
1686 | FileDef *fd = rootNav->fileDef();␊ |
1687 | QCString scName;␊ |
1688 | ␊ |
1689 | // see if the using statement was found inside a namespace or inside␊ |
1690 | // the global file scope.␊ |
1691 | if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)␊ |
1692 | {␊ |
1693 | scName=rootNav->parent()->name();␊ |
1694 | if (!scName.isEmpty())␊ |
1695 | {␊ |
1696 | nd = getResolvedNamespace(scName);␊ |
1697 | }␊ |
1698 | }␊ |
1699 | ␊ |
1700 | // Assume the using statement was used to import a class.␊ |
1701 | // Find the scope in which the `using' namespace is defined by prepending␊ |
1702 | // the possible scopes in which the using statement was found, starting␊ |
1703 | // with the most inner scope and going to the most outer scope (i.e. ␊ |
1704 | // file scope).␊ |
1705 | ␊ |
1706 | QCString name = substitute(root->name,".","::"); //Java/C# scope->internal␊ |
1707 | usingCd = getClass(name);␊ |
1708 | if (usingCd==0)␊ |
1709 | {␊ |
1710 | usingCd = Doxygen::hiddenClasses->find(name);␊ |
1711 | }␊ |
1712 | ␊ |
1713 | //printf("%s -> %p\n",root->name.data(),usingCd);␊ |
1714 | if (usingCd==0) // definition not in the input => add an artificial class␊ |
1715 | {␊ |
1716 | Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",␊ |
1717 | name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);␊ |
1718 | usingCd = new ClassDef(␊ |
1719 | "<using>",1,␊ |
1720 | name,ClassDef::Class);␊ |
1721 | Doxygen::hiddenClasses->append(root->name,usingCd);␊ |
1722 | usingCd->setArtificial(TRUE);␊ |
1723 | }␊ |
1724 | else␊ |
1725 | {␊ |
1726 | Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",␊ |
1727 | usingCd->name().data(),nd?nd->name().data():fd->name().data());␊ |
1728 | }␊ |
1729 | ␊ |
1730 | if (usingCd) // add the class to the correct scope␊ |
1731 | {␊ |
1732 | if (nd)␊ |
1733 | {␊ |
1734 | //printf("Inside namespace %s\n",nd->name().data());␊ |
1735 | nd->addUsingDeclaration(usingCd);␊ |
1736 | }␊ |
1737 | else if (fd)␊ |
1738 | {␊ |
1739 | //printf("Inside file %s\n",fd->name().data());␊ |
1740 | fd->addUsingDeclaration(usingCd);␊ |
1741 | }␊ |
1742 | }␊ |
1743 | }␊ |
1744 | ␊ |
1745 | rootNav->releaseEntry();␊ |
1746 | }␊ |
1747 | RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);␊ |
1748 | }␊ |
1749 | ␊ |
1750 | //----------------------------------------------------------------------␊ |
1751 | ␊ |
1752 | static void findUsingDeclImports(EntryNav *rootNav)␊ |
1753 | {␊ |
1754 | if (rootNav->section()==Entry::USINGDECL_SEC &&␊ |
1755 | (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member␊ |
1756 | )␊ |
1757 | {␊ |
1758 | //printf("Found using declaration %s at line %d of %s inside section %x\n",␊ |
1759 | // root->name.data(),root->startLine,root->fileName.data(),␊ |
1760 | // root->parent->section);␊ |
1761 | QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());␊ |
1762 | fullName=stripAnonymousNamespaceScope(fullName);␊ |
1763 | fullName=stripTemplateSpecifiersFromScope(fullName);␊ |
1764 | ClassDef *cd = getClass(fullName);␊ |
1765 | if (cd)␊ |
1766 | {␊ |
1767 | //printf("found class %s\n",cd->name().data());␊ |
1768 | int i=rootNav->name().find("::");␊ |
1769 | if (i!=-1)␊ |
1770 | {␊ |
1771 | QCString scope=rootNav->name().left(i);␊ |
1772 | QCString memName=rootNav->name().right(rootNav->name().length()-i-2);␊ |
1773 | ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter␊ |
1774 | if (bcd)␊ |
1775 | {␊ |
1776 | //printf("found class %s\n",bcd->name().data());␊ |
1777 | MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();␊ |
1778 | if (mndict)␊ |
1779 | {␊ |
1780 | MemberNameInfo *mni = mndict->find(memName);␊ |
1781 | if (mni)␊ |
1782 | {␊ |
1783 | MemberNameInfoIterator mnii(*mni); ␊ |
1784 | MemberInfo *mi;␊ |
1785 | for ( ; (mi=mnii.current()) ; ++mnii )␊ |
1786 | {␊ |
1787 | MemberDef *md = mi->memberDef;␊ |
1788 | if (md && md->protection()!=Private)␊ |
1789 | {␊ |
1790 | ␊ |
1791 | rootNav->loadEntry(g_storage);␊ |
1792 | Entry *root = rootNav->entry();␊ |
1793 | ␊ |
1794 | //printf("found member %s\n",mni->memberName());␊ |
1795 | MemberDef *newMd = 0;␊ |
1796 | {␊ |
1797 | LockingPtr<ArgumentList> templAl = md->templateArguments();␊ |
1798 | LockingPtr<ArgumentList> al = md->templateArguments();␊ |
1799 | newMd = new MemberDef(␊ |
1800 | root->fileName,root->startLine,␊ |
1801 | md->typeString(),memName,md->argsString(),␊ |
1802 | md->excpString(),root->protection,root->virt,␊ |
1803 | md->isStatic(),Member,md->memberType(),␊ |
1804 | templAl.pointer(),al.pointer()␊ |
1805 | );␊ |
1806 | }␊ |
1807 | newMd->setMemberClass(cd);␊ |
1808 | cd->insertMember(newMd);␊ |
1809 | if (!root->doc.isEmpty() || !root->brief.isEmpty())␊ |
1810 | {␊ |
1811 | newMd->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
1812 | newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1813 | newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
1814 | }␊ |
1815 | else␊ |
1816 | {␊ |
1817 | newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());␊ |
1818 | newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());␊ |
1819 | newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());␊ |
1820 | }␊ |
1821 | newMd->setDefinition(md->definition());␊ |
1822 | newMd->enableCallGraph(root->callGraph);␊ |
1823 | newMd->enableCallerGraph(root->callerGraph);␊ |
1824 | newMd->setBitfields(md->bitfieldString());␊ |
1825 | newMd->addSectionsToDefinition(root->anchors);␊ |
1826 | newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());␊ |
1827 | newMd->setBodyDef(md->getBodyDef());␊ |
1828 | newMd->setInitializer(md->initializer());␊ |
1829 | newMd->setMaxInitLines(md->initializerLines());␊ |
1830 | newMd->setMemberGroupId(root->mGrpId);␊ |
1831 | newMd->setMemberSpecifiers(md->getMemberSpecifiers());␊ |
1832 | ␊ |
1833 | rootNav->releaseEntry();␊ |
1834 | }␊ |
1835 | }␊ |
1836 | }␊ |
1837 | }␊ |
1838 | }␊ |
1839 | }␊ |
1840 | }␊ |
1841 | ␊ |
1842 | }␊ |
1843 | RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);␊ |
1844 | }␊ |
1845 | ␊ |
1846 | //----------------------------------------------------------------------␊ |
1847 | ␊ |
1848 | static void findIncludedUsingDirectives()␊ |
1849 | {␊ |
1850 | // first mark all files as not visited␊ |
1851 | FileNameListIterator fnli(*Doxygen::inputNameList); ␊ |
1852 | FileName *fn;␊ |
1853 | for (fnli.toFirst();(fn=fnli.current());++fnli)␊ |
1854 | {␊ |
1855 | FileNameIterator fni(*fn);␊ |
1856 | FileDef *fd;␊ |
1857 | for (;(fd=fni.current());++fni)␊ |
1858 | {␊ |
1859 | fd->visited=FALSE;␊ |
1860 | }␊ |
1861 | }␊ |
1862 | // then recursively add using directives found in #include files␊ |
1863 | // to files that have not been visited.␊ |
1864 | for (fnli.toFirst();(fn=fnli.current());++fnli)␊ |
1865 | {␊ |
1866 | FileNameIterator fni(*fn);␊ |
1867 | FileDef *fd;␊ |
1868 | for (fni.toFirst();(fd=fni.current());++fni)␊ |
1869 | {␊ |
1870 | if (!fd->visited) ␊ |
1871 | {␊ |
1872 | //printf("----- adding using directives for file %s\n",fd->name().data());␊ |
1873 | fd->addIncludedUsingDirectives();␊ |
1874 | }␊ |
1875 | }␊ |
1876 | }␊ |
1877 | }␊ |
1878 | ␊ |
1879 | //----------------------------------------------------------------------␊ |
1880 | ␊ |
1881 | static MemberDef *addVariableToClass(␊ |
1882 | EntryNav *rootNav,␊ |
1883 | ClassDef *cd,␊ |
1884 | MemberDef::MemberType mtype,␊ |
1885 | const QCString &name,␊ |
1886 | bool fromAnnScope,␊ |
1887 | MemberDef *fromAnnMemb,␊ |
1888 | Protection prot,␊ |
1889 | Relationship related)␊ |
1890 | {␊ |
1891 | Entry *root = rootNav->entry();␊ |
1892 | ␊ |
1893 | QCString qualScope = cd->qualifiedNameWithTemplateParameters();␊ |
1894 | QCString scopeSeparator="::";␊ |
1895 | if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))␊ |
1896 | {␊ |
1897 | qualScope = substitute(qualScope,"::",".");␊ |
1898 | scopeSeparator=".";␊ |
1899 | }␊ |
1900 | Debug::print(Debug::Variables,0,␊ |
1901 | " class variable:\n"␊ |
1902 | " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",␊ |
1903 | root->type.data(),␊ |
1904 | qualScope.data(), ␊ |
1905 | name.data(),␊ |
1906 | root->args.data(),␊ |
1907 | root->protection,␊ |
1908 | fromAnnScope,␊ |
1909 | root->initializer.data()␊ |
1910 | );␊ |
1911 | ␊ |
1912 | QCString def;␊ |
1913 | if (!root->type.isEmpty())␊ |
1914 | {␊ |
1915 | if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES"))␊ |
1916 | {␊ |
1917 | def=root->type+" "+name+root->args;␊ |
1918 | }␊ |
1919 | else␊ |
1920 | {␊ |
1921 | def=root->type+" "+qualScope+scopeSeparator+name+root->args;␊ |
1922 | }␊ |
1923 | }␊ |
1924 | else␊ |
1925 | {␊ |
1926 | if (Config_getBool("HIDE_SCOPE_NAMES"))␊ |
1927 | {␊ |
1928 | def=name+root->args;␊ |
1929 | }␊ |
1930 | else␊ |
1931 | {␊ |
1932 | def=qualScope+scopeSeparator+name+root->args;␊ |
1933 | }␊ |
1934 | }␊ |
1935 | def.stripPrefix("static ");␊ |
1936 | ␊ |
1937 | // see if the member is already found in the same scope␊ |
1938 | // (this may be the case for a static member that is initialized␊ |
1939 | // outside the class)␊ |
1940 | MemberName *mn=Doxygen::memberNameSDict->find(name);␊ |
1941 | if (mn)␊ |
1942 | {␊ |
1943 | MemberNameIterator mni(*mn);␊ |
1944 | MemberDef *md;␊ |
1945 | for (mni.toFirst();(md=mni.current());++mni)␊ |
1946 | {␊ |
1947 | //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",␊ |
1948 | // md->getClassDef(),cd,root->type.data(),md->typeString());␊ |
1949 | if (md->getClassDef()==cd && ␊ |
1950 | removeRedundantWhiteSpace(root->type)==md->typeString()) ␊ |
1951 | // member already in the scope␊ |
1952 | {␊ |
1953 | ␊ |
1954 | if (root->lang==SrcLangExt_ObjC && ␊ |
1955 | root->mtype==Property && ␊ |
1956 | md->memberType()==MemberDef::Variable)␊ |
1957 | { // Objective-C 2.0 property␊ |
1958 | // turn variable into a property␊ |
1959 | md->setProtection(root->protection);␊ |
1960 | cd->reclassifyMember(md,MemberDef::Property);␊ |
1961 | }␊ |
1962 | addMemberDocs(rootNav,md,def,0,FALSE);␊ |
1963 | //printf(" Member already found!\n");␊ |
1964 | return md;␊ |
1965 | }␊ |
1966 | } ␊ |
1967 | }␊ |
1968 | ␊ |
1969 | // new member variable, typedef or enum value␊ |
1970 | MemberDef *md=new MemberDef(␊ |
1971 | root->fileName,root->startLine,␊ |
1972 | root->type,name,root->args,0,␊ |
1973 | prot,Normal,root->stat,related,␊ |
1974 | mtype,0,0);␊ |
1975 | md->setTagInfo(rootNav->tagInfo());␊ |
1976 | md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())␊ |
1977 | //md->setDefFile(root->fileName);␊ |
1978 | //md->setDefLine(root->startLine);␊ |
1979 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
1980 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
1981 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
1982 | md->setDefinition(def);␊ |
1983 | md->setBitfields(root->bitfields);␊ |
1984 | md->addSectionsToDefinition(root->anchors);␊ |
1985 | md->setFromAnonymousScope(fromAnnScope);␊ |
1986 | md->setFromAnonymousMember(fromAnnMemb);␊ |
1987 | //md->setIndentDepth(indentDepth);␊ |
1988 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
1989 | md->setInitializer(root->initializer);␊ |
1990 | md->setMaxInitLines(root->initLines);␊ |
1991 | md->setMemberGroupId(root->mGrpId);␊ |
1992 | md->setMemberSpecifiers(root->spec);␊ |
1993 | md->setReadAccessor(root->read);␊ |
1994 | md->setWriteAccessor(root->write);␊ |
1995 | md->enableCallGraph(root->callGraph);␊ |
1996 | md->enableCallerGraph(root->callerGraph);␊ |
1997 | md->setHidden(root->hidden);␊ |
1998 | md->setArtificial(root->artificial);␊ |
1999 | addMemberToGroups(root,md);␊ |
2000 | //if (root->mGrpId!=-1) ␊ |
2001 | //{␊ |
2002 | // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);␊ |
2003 | // md->setMemberGroup(memberGroupDict[root->mGrpId]);␊ |
2004 | //␊ |
2005 | md->setBodyDef(rootNav->fileDef());␊ |
2006 | ␊ |
2007 | //printf(" Adding member=%s\n",md->name().data());␊ |
2008 | // add the member to the global list␊ |
2009 | if (mn)␊ |
2010 | {␊ |
2011 | mn->append(md);␊ |
2012 | }␊ |
2013 | else // new variable name␊ |
2014 | {␊ |
2015 | mn = new MemberName(name);␊ |
2016 | mn->append(md);␊ |
2017 | //printf("Adding memberName=%s\n",mn->memberName());␊ |
2018 | //Doxygen::memberNameDict.insert(name,mn);␊ |
2019 | //Doxygen::memberNameList.append(mn);␊ |
2020 | Doxygen::memberNameSDict->append(name,mn);␊ |
2021 | // add the member to the class␊ |
2022 | }␊ |
2023 | //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);␊ |
2024 | cd->insertMember(md);␊ |
2025 | md->setRefItems(root->sli);␊ |
2026 | ␊ |
2027 | //TODO: insert FileDef instead of filename strings.␊ |
2028 | cd->insertUsedFile(root->fileName);␊ |
2029 | rootNav->changeSection(Entry::EMPTY_SEC);␊ |
2030 | return md;␊ |
2031 | }␊ |
2032 | ␊ |
2033 | //----------------------------------------------------------------------␊ |
2034 | ␊ |
2035 | static MemberDef *addVariableToFile(␊ |
2036 | EntryNav *rootNav,␊ |
2037 | MemberDef::MemberType mtype,␊ |
2038 | const QCString &scope,␊ |
2039 | const QCString &name,␊ |
2040 | bool fromAnnScope,␊ |
2041 | /*int indentDepth,*/␊ |
2042 | MemberDef *fromAnnMemb)␊ |
2043 | {␊ |
2044 | Entry *root = rootNav->entry();␊ |
2045 | Debug::print(Debug::Variables,0,␊ |
2046 | " global variable:\n"␊ |
2047 | " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d\n",␊ |
2048 | root->type.data(),␊ |
2049 | scope.data(), ␊ |
2050 | name.data(),␊ |
2051 | root->args.data(),␊ |
2052 | root->protection,␊ |
2053 | mtype␊ |
2054 | );␊ |
2055 | ␊ |
2056 | FileDef *fd = rootNav->fileDef();␊ |
2057 | ␊ |
2058 | // see if we have a typedef that should hide a struct or union␊ |
2059 | if (mtype==MemberDef::Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))␊ |
2060 | {␊ |
2061 | QCString type = root->type;␊ |
2062 | type.stripPrefix("typedef ");␊ |
2063 | if (type.left(7)=="struct " || type.left(6)=="union ")␊ |
2064 | {␊ |
2065 | type.stripPrefix("struct ");␊ |
2066 | type.stripPrefix("union ");␊ |
2067 | static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");␊ |
2068 | int l,s;␊ |
2069 | s = re.match(type,0,&l);␊ |
2070 | if (s>=0)␊ |
2071 | {␊ |
2072 | QCString typeValue = type.mid(s,l);␊ |
2073 | ClassDef *cd = getClass(typeValue);␊ |
2074 | if (cd)␊ |
2075 | {␊ |
2076 | // this typedef should hide compound name cd, so we␊ |
2077 | // change the name that is displayed from cd.␊ |
2078 | cd->setClassName(name);␊ |
2079 | cd->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
2080 | cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
2081 | return 0;␊ |
2082 | }␊ |
2083 | }␊ |
2084 | }␊ |
2085 | }␊ |
2086 | ␊ |
2087 | // see if the function is inside a namespace␊ |
2088 | NamespaceDef *nd = 0;␊ |
2089 | QCString nscope;␊ |
2090 | if (!scope.isEmpty())␊ |
2091 | {␊ |
2092 | if (scope.find('@')!=-1) return 0; // anonymous scope!␊ |
2093 | //nscope=removeAnonymousScopes(scope);␊ |
2094 | //if (!nscope.isEmpty())␊ |
2095 | //{␊ |
2096 | nd = getResolvedNamespace(scope);␊ |
2097 | //}␊ |
2098 | }␊ |
2099 | QCString def;␊ |
2100 | ␊ |
2101 | // determine the definition of the global variable␊ |
2102 | if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' && ␊ |
2103 | !Config_getBool("HIDE_SCOPE_NAMES")␊ |
2104 | )␊ |
2105 | // variable is inside a namespace, so put the scope before the name␊ |
2106 | {␊ |
2107 | static bool optimizeForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA");␊ |
2108 | QCString sep="::";␊ |
2109 | if (optimizeForJava) sep=".";␊ |
2110 | ␊ |
2111 | if (!root->type.isEmpty())␊ |
2112 | {␊ |
2113 | def=root->type+" "+nd->name()+sep+name+root->args;␊ |
2114 | }␊ |
2115 | else␊ |
2116 | {␊ |
2117 | def=nd->name()+sep+name+root->args;␊ |
2118 | }␊ |
2119 | }␊ |
2120 | else␊ |
2121 | {␊ |
2122 | if (!root->type.isEmpty() && !root->name.isEmpty())␊ |
2123 | {␊ |
2124 | if (name.at(0)=='@') // dummy variable representing anonymous union␊ |
2125 | def=root->type;␊ |
2126 | else␊ |
2127 | def=root->type+" "+name+root->args;␊ |
2128 | }␊ |
2129 | else␊ |
2130 | {␊ |
2131 | def=name+root->args;␊ |
2132 | }␊ |
2133 | }␊ |
2134 | def.stripPrefix("static ");␊ |
2135 | ␊ |
2136 | MemberName *mn=Doxygen::functionNameSDict->find(name);␊ |
2137 | if (mn)␊ |
2138 | {␊ |
2139 | //QCString nscope=removeAnonymousScopes(scope);␊ |
2140 | //NamespaceDef *nd=0;␊ |
2141 | //if (!nscope.isEmpty())␊ |
2142 | if (!scope.isEmpty())␊ |
2143 | {␊ |
2144 | nd = getResolvedNamespace(scope);␊ |
2145 | }␊ |
2146 | MemberNameIterator mni(*mn);␊ |
2147 | MemberDef *md;␊ |
2148 | for (mni.toFirst();(md=mni.current());++mni)␊ |
2149 | {␊ |
2150 | if (␊ |
2151 | ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() && ␊ |
2152 | root->fileName==md->getFileDef()->absFilePath()␊ |
2153 | ) // both variable names in the same file␊ |
2154 | || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace␊ |
2155 | )␊ |
2156 | && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables␊ |
2157 | && !md->isEnumerate() // in C# an enum value and enum can have the same name␊ |
2158 | )␊ |
2159 | // variable already in the scope␊ |
2160 | {␊ |
2161 | if (md->getFileDef() &&␊ |
2162 | ! // not a php array␊ |
2163 | (␊ |
2164 | (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) &&␊ |
2165 | (md->argsString()!=root->args && root->args.find('[')!=-1)␊ |
2166 | )␊ |
2167 | ) ␊ |
2168 | // not a php array variable␊ |
2169 | {␊ |
2170 | ␊ |
2171 | Debug::print(Debug::Variables,0,␊ |
2172 | " variable already found: scope=%s\n",md->getOuterScope()->name().data());␊ |
2173 | addMemberDocs(rootNav,md,def,0,FALSE);␊ |
2174 | md->setRefItems(root->sli);␊ |
2175 | return md;␊ |
2176 | }␊ |
2177 | }␊ |
2178 | } ␊ |
2179 | }␊ |
2180 | Debug::print(Debug::Variables,0,␊ |
2181 | " new variable, nd=%s!\n",nd?nd->name().data():"<global>");␊ |
2182 | // new global variable, enum value or typedef␊ |
2183 | MemberDef *md=new MemberDef(␊ |
2184 | root->fileName,root->startLine,␊ |
2185 | root->type,name,root->args,0,␊ |
2186 | Public, Normal,root->stat,Member,␊ |
2187 | mtype,0,0);␊ |
2188 | md->setTagInfo(rootNav->tagInfo());␊ |
2189 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
2190 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
2191 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
2192 | md->addSectionsToDefinition(root->anchors);␊ |
2193 | md->setFromAnonymousScope(fromAnnScope);␊ |
2194 | md->setFromAnonymousMember(fromAnnMemb);␊ |
2195 | md->setInitializer(root->initializer);␊ |
2196 | md->setMaxInitLines(root->initLines);␊ |
2197 | md->setMemberGroupId(root->mGrpId);␊ |
2198 | md->setDefinition(def);␊ |
2199 | md->enableCallGraph(root->callGraph);␊ |
2200 | md->enableCallerGraph(root->callerGraph);␊ |
2201 | md->setExplicitExternal(root->explicitExternal);␊ |
2202 | //md->setOuterScope(fd);␊ |
2203 | if (!root->explicitExternal)␊ |
2204 | {␊ |
2205 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
2206 | md->setBodyDef(fd);␊ |
2207 | }␊ |
2208 | addMemberToGroups(root,md);␊ |
2209 | ␊ |
2210 | md->setRefItems(root->sli);␊ |
2211 | if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')␊ |
2212 | {␊ |
2213 | md->setNamespace(nd);␊ |
2214 | nd->insertMember(md); ␊ |
2215 | }␊ |
2216 | ␊ |
2217 | // add member to the file (we do this even if we have already inserted␊ |
2218 | // it into the namespace. ␊ |
2219 | if (fd)␊ |
2220 | {␊ |
2221 | md->setFileDef(fd); ␊ |
2222 | fd->insertMember(md);␊ |
2223 | }␊ |
2224 | ␊ |
2225 | // add member definition to the list of globals ␊ |
2226 | if (mn)␊ |
2227 | {␊ |
2228 | mn->append(md);␊ |
2229 | }␊ |
2230 | else␊ |
2231 | {␊ |
2232 | mn = new MemberName(name);␊ |
2233 | mn->append(md);␊ |
2234 | Doxygen::functionNameSDict->append(name,mn);␊ |
2235 | }␊ |
2236 | rootNav->changeSection(Entry::EMPTY_SEC);␊ |
2237 | return md;␊ |
2238 | }␊ |
2239 | ␊ |
2240 | /*! See if the return type string \a type is that of a function pointer ␊ |
2241 | * \returns -1 if this is not a function pointer variable or␊ |
2242 | * the index at which the brace of (...*name) was found.␊ |
2243 | */␊ |
2244 | static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)␊ |
2245 | {␊ |
2246 | if (lang == SrcLangExt_F90) return -1; // Fortran does not have function pointers␊ |
2247 | static const QRegExp re("([^)]*[\\*\\^][^)]*)");␊ |
2248 | int i=-1,l;␊ |
2249 | if (!type.isEmpty() && // return type is non-empty␊ |
2250 | (i=re.match(type,0,&l))!=-1 && // contains (...*...)␊ |
2251 | type.find("operator")==-1 && // not an operator␊ |
2252 | (type.find(")(")==-1 || type.find("typedef ")!=-1)␊ |
2253 | // not a function pointer return type␊ |
2254 | )␊ |
2255 | {␊ |
2256 | if (pLength) *pLength=l;␊ |
2257 | //printf("findFunctionPtr=%d\n",i);␊ |
2258 | return i;␊ |
2259 | }␊ |
2260 | else␊ |
2261 | {␊ |
2262 | //printf("findFunctionPtr=%d\n",-1);␊ |
2263 | return -1;␊ |
2264 | }␊ |
2265 | }␊ |
2266 | ␊ |
2267 | ␊ |
2268 | /*! Returns TRUE iff \a type is a class within scope \a context.␊ |
2269 | * Used to detect variable declarations that look like function prototypes.␊ |
2270 | */␊ |
2271 | static bool isVarWithConstructor(EntryNav *rootNav)␊ |
2272 | {␊ |
2273 | static QRegExp initChars("[0-9\"'&*!^]+");␊ |
2274 | static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");␊ |
2275 | bool result=FALSE;␊ |
2276 | bool typeIsClass;␊ |
2277 | QCString type;␊ |
2278 | Definition *ctx = 0;␊ |
2279 | FileDef *fd = 0;␊ |
2280 | int ti;␊ |
2281 | ␊ |
2282 | //printf("isVarWithConstructor(%s)\n",rootNav->name().data());␊ |
2283 | rootNav->loadEntry(g_storage);␊ |
2284 | Entry *root = rootNav->entry();␊ |
2285 | ␊ |
2286 | if (rootNav->parent()->section() & Entry::COMPOUND_MASK)␊ |
2287 | { // inside a class␊ |
2288 | result=FALSE;␊ |
2289 | goto done;␊ |
2290 | }␊ |
2291 | else if ((fd = rootNav->fileDef()) &&␊ |
2292 | (fd->name().right(2)==".c" || fd->name().right(2)==".h")␊ |
2293 | )␊ |
2294 | { // inside a .c file␊ |
2295 | result=FALSE;␊ |
2296 | goto done;␊ |
2297 | }␊ |
2298 | if (root->type.isEmpty()) ␊ |
2299 | {␊ |
2300 | result=FALSE;␊ |
2301 | goto done;␊ |
2302 | }␊ |
2303 | if (!rootNav->parent()->name().isEmpty()) ␊ |
2304 | {␊ |
2305 | ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());␊ |
2306 | }␊ |
2307 | type = root->type;␊ |
2308 | // remove qualifiers␊ |
2309 | findAndRemoveWord(type,"const");␊ |
2310 | findAndRemoveWord(type,"static");␊ |
2311 | findAndRemoveWord(type,"volatile");␊ |
2312 | //if (type.left(6)=="const ") type=type.right(type.length()-6);␊ |
2313 | typeIsClass=getResolvedClass(ctx,fd,type)!=0;␊ |
2314 | if (!typeIsClass && (ti=type.find('<'))!=-1)␊ |
2315 | {␊ |
2316 | typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;␊ |
2317 | }␊ |
2318 | if (typeIsClass) // now we still have to check if the arguments are ␊ |
2319 | // types or values. Since we do not have complete type info␊ |
2320 | // we need to rely on heuristics :-(␊ |
2321 | {␊ |
2322 | //printf("typeIsClass\n");␊ |
2323 | ArgumentList *al = root->argList;␊ |
2324 | if (al==0 || al->isEmpty()) ␊ |
2325 | {␊ |
2326 | result=FALSE; // empty arg list -> function prototype.␊ |
2327 | goto done;␊ |
2328 | }␊ |
2329 | ArgumentListIterator ali(*al);␊ |
2330 | Argument *a;␊ |
2331 | for (ali.toFirst();(a=ali.current());++ali)␊ |
2332 | {␊ |
2333 | if (!a->name.isEmpty() || !a->defval.isEmpty()) ␊ |
2334 | {␊ |
2335 | if (a->name.find(initChars)==0)␊ |
2336 | {␊ |
2337 | result=TRUE;␊ |
2338 | }␊ |
2339 | else␊ |
2340 | {␊ |
2341 | result=FALSE; // arg has (type,name) pair -> function prototype␊ |
2342 | }␊ |
2343 | goto done;␊ |
2344 | }␊ |
2345 | if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0) ␊ |
2346 | {␊ |
2347 | result=FALSE; // arg type is a known type␊ |
2348 | goto done;␊ |
2349 | }␊ |
2350 | if (checkIfTypedef(ctx,fd,a->type))␊ |
2351 | {␊ |
2352 | //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);␊ |
2353 | result=FALSE; // argument is a typedef␊ |
2354 | goto done;␊ |
2355 | }␊ |
2356 | if (a->type.at(a->type.length()-1)=='*' ||␊ |
2357 | a->type.at(a->type.length()-1)=='&') ␊ |
2358 | // type ends with * or & => pointer or reference␊ |
2359 | {␊ |
2360 | result=FALSE;␊ |
2361 | goto done;␊ |
2362 | }␊ |
2363 | if (a->type.find(initChars)==0) ␊ |
2364 | {␊ |
2365 | result=TRUE; // argument type starts with typical initializer char␊ |
2366 | goto done;␊ |
2367 | }␊ |
2368 | QCString resType=resolveTypeDef(ctx,a->type);␊ |
2369 | if (resType.isEmpty()) resType=a->type;␊ |
2370 | int len;␊ |
2371 | if (idChars.match(resType,0,&len)==0) // resType starts with identifier␊ |
2372 | {␊ |
2373 | resType=resType.left(len);␊ |
2374 | //printf("resType=%s\n",resType.data());␊ |
2375 | if (resType=="int" || resType=="long" || resType=="float" || ␊ |
2376 | resType=="double" || resType=="char" || resType=="signed" || ␊ |
2377 | resType=="const" || resType=="unsigned" || resType=="void") ␊ |
2378 | {␊ |
2379 | result=FALSE; // type keyword -> function prototype␊ |
2380 | goto done;␊ |
2381 | }␊ |
2382 | }␊ |
2383 | }␊ |
2384 | result=TRUE;␊ |
2385 | }␊ |
2386 | ␊ |
2387 | done:␊ |
2388 | //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),␊ |
2389 | // root->type.data(),result);␊ |
2390 | rootNav->releaseEntry();␊ |
2391 | return result;␊ |
2392 | }␊ |
2393 | ␊ |
2394 | static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)␊ |
2395 | {␊ |
2396 | rootNav->loadEntry(g_storage);␊ |
2397 | Entry *root = rootNav->entry();␊ |
2398 | ␊ |
2399 | Debug::print(Debug::Variables,0,␊ |
2400 | "VARIABLE_SEC: \n"␊ |
2401 | " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d\n",␊ |
2402 | root->type.data(),␊ |
2403 | root->name.data(),␊ |
2404 | root->args.data(),␊ |
2405 | root->bodyLine,␊ |
2406 | root->mGrpId␊ |
2407 | );␊ |
2408 | //printf("root->parent->name=%s\n",root->parent->name.data());␊ |
2409 | ␊ |
2410 | if (root->type.isEmpty() && root->name.find("operator")==-1 &&␊ |
2411 | (root->name.find('*')!=-1 || root->name.find('&')!=-1))␊ |
2412 | {␊ |
2413 | // recover from parse error caused by redundant braces ␊ |
2414 | // like in "int *(var[10]);", which is parsed as␊ |
2415 | // type="" name="int *" args="(var[10])"␊ |
2416 | ␊ |
2417 | root->type=root->name;␊ |
2418 | static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");␊ |
2419 | int l;␊ |
2420 | int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);␊ |
2421 | root->name=root->args.mid(i,l);␊ |
2422 | root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);␊ |
2423 | //printf("new: type=`%s' name=`%s' args=`%s'\n",␊ |
2424 | // root->type.data(),root->name.data(),root->args.data());␊ |
2425 | }␊ |
2426 | else␊ |
2427 | {␊ |
2428 | int i=isFuncPtr;␊ |
2429 | if (i==-1) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set␊ |
2430 | if (i!=-1) // function pointer␊ |
2431 | {␊ |
2432 | int ai = root->type.find('[',i);␊ |
2433 | if (ai>i) // function pointer array␊ |
2434 | {␊ |
2435 | root->args.prepend(root->type.right(root->type.length()-ai));␊ |
2436 | root->type=root->type.left(ai);␊ |
2437 | }␊ |
2438 | else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"␊ |
2439 | {␊ |
2440 | root->type=root->type.left(root->type.length()-1);␊ |
2441 | root->args.prepend(")");␊ |
2442 | //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());␊ |
2443 | }␊ |
2444 | }␊ |
2445 | else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)␊ |
2446 | {␊ |
2447 | root->type=root->type.left(root->type.length()-1);␊ |
2448 | root->args.prepend(")");␊ |
2449 | }␊ |
2450 | }␊ |
2451 | ␊ |
2452 | QCString scope,name=removeRedundantWhiteSpace(root->name);␊ |
2453 | ␊ |
2454 | // find the scope of this variable ␊ |
2455 | EntryNav *p = rootNav->parent();␊ |
2456 | while ((p->section() & Entry::SCOPE_MASK))␊ |
2457 | {␊ |
2458 | QCString scopeName = p->name();␊ |
2459 | if (!scopeName.isEmpty())␊ |
2460 | {␊ |
2461 | scope.prepend(scopeName);␊ |
2462 | break;␊ |
2463 | }␊ |
2464 | p=p->parent();␊ |
2465 | }␊ |
2466 | ␊ |
2467 | MemberDef::MemberType mtype;␊ |
2468 | QCString type=root->type.stripWhiteSpace();␊ |
2469 | ClassDef *cd=0;␊ |
2470 | bool isRelated=FALSE;␊ |
2471 | bool isMemberOf=FALSE;␊ |
2472 | ␊ |
2473 | QCString classScope=stripAnonymousNamespaceScope(scope);␊ |
2474 | classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);␊ |
2475 | QCString annScopePrefix=scope.left(scope.length()-classScope.length());␊ |
2476 | ␊ |
2477 | if (root->name.findRev("::")!=-1) ␊ |
2478 | {␊ |
2479 | if (root->type=="friend class" || root->type=="friend struct" || ␊ |
2480 | root->type=="friend union")␊ |
2481 | {␊ |
2482 | cd=getClass(scope);␊ |
2483 | if (cd)␊ |
2484 | {␊ |
2485 | addVariableToClass(rootNav, // entry␊ |
2486 | cd, // class to add member to␊ |
2487 | MemberDef::Friend, // type of member␊ |
2488 | name, // name of the member␊ |
2489 | FALSE, // from Anonymous scope␊ |
2490 | 0, // anonymous member␊ |
2491 | Public, // protection␊ |
2492 | Member // related to a class␊ |
2493 | );␊ |
2494 | }␊ |
2495 | }␊ |
2496 | goto nextMember;␊ |
2497 | /* skip this member, because it is a ␊ |
2498 | * static variable definition (always?), which will be␊ |
2499 | * found in a class scope as well, but then we know the␊ |
2500 | * correct protection level, so only then it will be␊ |
2501 | * inserted in the correct list!␊ |
2502 | */␊ |
2503 | }␊ |
2504 | ␊ |
2505 | if (type=="@") ␊ |
2506 | mtype=MemberDef::EnumValue;␊ |
2507 | else if (type.left(8)=="typedef ") ␊ |
2508 | mtype=MemberDef::Typedef;␊ |
2509 | else if (type.left(7)=="friend ")␊ |
2510 | mtype=MemberDef::Friend;␊ |
2511 | else if (root->mtype==Property)␊ |
2512 | mtype=MemberDef::Property;␊ |
2513 | else if (root->mtype==Event)␊ |
2514 | mtype=MemberDef::Event;␊ |
2515 | else␊ |
2516 | mtype=MemberDef::Variable;␊ |
2517 | ␊ |
2518 | if (!root->relates.isEmpty()) // related variable␊ |
2519 | {␊ |
2520 | isRelated=TRUE;␊ |
2521 | isMemberOf=(root->relatesType == MemberOf);␊ |
2522 | if (getClass(root->relates)==0 && !scope.isEmpty())␊ |
2523 | scope=mergeScopes(scope,root->relates);␊ |
2524 | else ␊ |
2525 | scope=root->relates;␊ |
2526 | }␊ |
2527 | ␊ |
2528 | cd=getClass(scope);␊ |
2529 | if (cd==0 && classScope!=scope) cd=getClass(classScope);␊ |
2530 | if (cd)␊ |
2531 | {␊ |
2532 | MemberDef *md=0;␊ |
2533 | ␊ |
2534 | // if cd is an anonymous scope we insert the member ␊ |
2535 | // into a non-anonymous scope as well. This is needed to␊ |
2536 | // be able to refer to it using \var or \fn␊ |
2537 | ␊ |
2538 | //int indentDepth=0;␊ |
2539 | int si=scope.find('@');␊ |
2540 | //int anonyScopes = 0;␊ |
2541 | bool added=FALSE;␊ |
2542 | ␊ |
2543 | if (si!=-1) // anonymous scope␊ |
2544 | {␊ |
2545 | QCString pScope;␊ |
2546 | ClassDef *pcd=0;␊ |
2547 | pScope = scope.left(QMAX(si-2,0));␊ |
2548 | if (!pScope.isEmpty())␊ |
2549 | pScope.prepend(annScopePrefix);␊ |
2550 | else if (annScopePrefix.length()>2)␊ |
2551 | pScope=annScopePrefix.left(annScopePrefix.length()-2);␊ |
2552 | if (name.at(0)!='@')␊ |
2553 | {␊ |
2554 | if (!pScope.isEmpty() && (pcd=getClass(pScope)))␊ |
2555 | {␊ |
2556 | md=addVariableToClass(rootNav, // entry␊ |
2557 | pcd, // class to add member to␊ |
2558 | mtype, // member type␊ |
2559 | name, // member name␊ |
2560 | TRUE, // from anonymous scope␊ |
2561 | 0, // from anonymous member␊ |
2562 | root->protection,␊ |
2563 | isMemberOf ? Foreign : isRelated ? Related : Member␊ |
2564 | );␊ |
2565 | added=TRUE;␊ |
2566 | }␊ |
2567 | else // anonymous scope inside namespace or file => put variable in the global scope␊ |
2568 | {␊ |
2569 | if (mtype==MemberDef::Variable)␊ |
2570 | {␊ |
2571 | md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0); ␊ |
2572 | }␊ |
2573 | added=TRUE;␊ |
2574 | }␊ |
2575 | }␊ |
2576 | }␊ |
2577 | ␊ |
2578 | //printf("name=`%s' scope=%s scope.right=%s\n",␊ |
2579 | // name.data(),scope.data(),␊ |
2580 | // scope.right(scope.length()-si).data());␊ |
2581 | addVariableToClass(rootNav, // entry␊ |
2582 | cd, // class to add member to␊ |
2583 | mtype, // member type␊ |
2584 | name, // name of the member␊ |
2585 | FALSE, // from anonymous scope␊ |
2586 | md, // from anonymous member␊ |
2587 | root->protection, ␊ |
2588 | isMemberOf ? Foreign : isRelated ? Related : Member);␊ |
2589 | }␊ |
2590 | else if (!name.isEmpty()) // global variable␊ |
2591 | {␊ |
2592 | //printf("Inserting member in global scope %s!\n",scope.data());␊ |
2593 | addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);␊ |
2594 | }␊ |
2595 | ␊ |
2596 | nextMember:␊ |
2597 | rootNav->releaseEntry();␊ |
2598 | }␊ |
2599 | ␊ |
2600 | //----------------------------------------------------------------------␊ |
2601 | // Searches the Entry tree for typedef documentation sections.␊ |
2602 | // If found they are stored in their class or in the global list.␊ |
2603 | static void buildTypedefList(EntryNav *rootNav)␊ |
2604 | {␊ |
2605 | //printf("buildVarList(%s)\n",rootNav->name().data());␊ |
2606 | if (!rootNav->name().isEmpty() &&␊ |
2607 | rootNav->section()==Entry::VARIABLE_SEC &&␊ |
2608 | rootNav->type().find("typedef ")!=-1 // its a typedef␊ |
2609 | ) ␊ |
2610 | {␊ |
2611 | addVariable(rootNav);␊ |
2612 | }␊ |
2613 | if (rootNav->children())␊ |
2614 | {␊ |
2615 | EntryNavListIterator eli(*rootNav->children());␊ |
2616 | EntryNav *e;␊ |
2617 | for (;(e=eli.current());++eli)␊ |
2618 | {␊ |
2619 | if (e->section()!=Entry::ENUM_SEC) ␊ |
2620 | {␊ |
2621 | buildTypedefList(e);␊ |
2622 | }␊ |
2623 | }␊ |
2624 | }␊ |
2625 | }␊ |
2626 | ␊ |
2627 | //----------------------------------------------------------------------␊ |
2628 | // Searches the Entry tree for Variable documentation sections.␊ |
2629 | // If found they are stored in their class or in the global list.␊ |
2630 | ␊ |
2631 | static void buildVarList(EntryNav *rootNav)␊ |
2632 | {␊ |
2633 | //printf("buildVarList(%s)\n",rootNav->name().data());␊ |
2634 | int isFuncPtr=-1;␊ |
2635 | if (!rootNav->name().isEmpty() &&␊ |
2636 | (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&␊ |
2637 | (␊ |
2638 | (rootNav->section()==Entry::VARIABLE_SEC // it's a variable␊ |
2639 | ) ||␊ |
2640 | (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable ␊ |
2641 | (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1␊ |
2642 | ) ||␊ |
2643 | (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor␊ |
2644 | isVarWithConstructor(rootNav)␊ |
2645 | )␊ |
2646 | ) ␊ |
2647 | ) // documented variable␊ |
2648 | {␊ |
2649 | addVariable(rootNav,isFuncPtr);␊ |
2650 | }␊ |
2651 | if (rootNav->children())␊ |
2652 | {␊ |
2653 | EntryNavListIterator eli(*rootNav->children());␊ |
2654 | EntryNav *e;␊ |
2655 | for (;(e=eli.current());++eli)␊ |
2656 | {␊ |
2657 | if (e->section()!=Entry::ENUM_SEC) ␊ |
2658 | {␊ |
2659 | buildVarList(e);␊ |
2660 | }␊ |
2661 | }␊ |
2662 | }␊ |
2663 | }␊ |
2664 | ␊ |
2665 | //----------------------------------------------------------------------␊ |
2666 | // Searches the Entry tree for Function sections.␊ |
2667 | // If found they are stored in their class or in the global list.␊ |
2668 | ␊ |
2669 | static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,␊ |
2670 | const QCString &rname,bool isFriend)␊ |
2671 | {␊ |
2672 | Entry *root = rootNav->entry();␊ |
2673 | FileDef *fd=rootNav->fileDef();␊ |
2674 | ␊ |
2675 | int l,i=-1;␊ |
2676 | static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");␊ |
2677 | ␊ |
2678 | if (!root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable␊ |
2679 | {␊ |
2680 | root->args+=root->type.right(root->type.length()-i-l);␊ |
2681 | root->type=root->type.left(i+l);␊ |
2682 | }␊ |
2683 | ␊ |
2684 | QCString name=removeRedundantWhiteSpace(rname);␊ |
2685 | if (name.left(2)=="::") name=name.right(name.length()-2);␊ |
2686 | ␊ |
2687 | MemberDef::MemberType mtype;␊ |
2688 | if (isFriend) mtype=MemberDef::Friend;␊ |
2689 | else if (root->mtype==Signal) mtype=MemberDef::Signal;␊ |
2690 | else if (root->mtype==Slot) mtype=MemberDef::Slot;␊ |
2691 | else if (root->mtype==DCOP) mtype=MemberDef::DCOP;␊ |
2692 | else mtype=MemberDef::Function;␊ |
2693 | ␊ |
2694 | // strip redundant template specifier for constructors␊ |
2695 | if ((fd==0 || getLanguageFromFileName(fd->name())==SrcLangExt_Cpp) &&␊ |
2696 | name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)␊ |
2697 | {␊ |
2698 | name=name.left(i); ␊ |
2699 | }␊ |
2700 | ␊ |
2701 | //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n", ␊ |
2702 | // root->name.data(),root->args.data(),argListToString(root->argList).data()␊ |
2703 | // );␊ |
2704 | ␊ |
2705 | // adding class member␊ |
2706 | MemberDef *md=new MemberDef(␊ |
2707 | root->fileName,root->startLine,␊ |
2708 | root->type,name,root->args,root->exception,␊ |
2709 | root->protection,root->virt,␊ |
2710 | root->stat && root->relatesType != MemberOf,␊ |
2711 | root->relates.isEmpty() ? Member :␊ |
2712 | root->relatesType == MemberOf ? Foreign : Related,␊ |
2713 | mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList);␊ |
2714 | md->setTagInfo(rootNav->tagInfo());␊ |
2715 | md->setMemberClass(cd);␊ |
2716 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
2717 | md->setDocsForDefinition(!root->proto);␊ |
2718 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
2719 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
2720 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
2721 | md->setMemberSpecifiers(root->spec);␊ |
2722 | md->setMemberGroupId(root->mGrpId);␊ |
2723 | md->setTypeConstraints(root->typeConstr);␊ |
2724 | md->setBodyDef(fd);␊ |
2725 | md->setFileDef(fd);␊ |
2726 | //md->setScopeTemplateArguments(root->tArgList);␊ |
2727 | md->addSectionsToDefinition(root->anchors);␊ |
2728 | QCString def;␊ |
2729 | QCString qualScope = cd->qualifiedNameWithTemplateParameters();␊ |
2730 | QCString scopeSeparator="::";␊ |
2731 | if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))␊ |
2732 | {␊ |
2733 | qualScope = substitute(qualScope,"::",".");␊ |
2734 | scopeSeparator=".";␊ |
2735 | }␊ |
2736 | if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))␊ |
2737 | {␊ |
2738 | if (!root->type.isEmpty())␊ |
2739 | {␊ |
2740 | if (root->argList)␊ |
2741 | {␊ |
2742 | def=root->type+" "+name;␊ |
2743 | }␊ |
2744 | else␊ |
2745 | {␊ |
2746 | def=root->type+" "+name+root->args;␊ |
2747 | }␊ |
2748 | }␊ |
2749 | else␊ |
2750 | {␊ |
2751 | if (root->argList)␊ |
2752 | {␊ |
2753 | def=name;␊ |
2754 | }␊ |
2755 | else␊ |
2756 | {␊ |
2757 | def=name+root->args;␊ |
2758 | }␊ |
2759 | }␊ |
2760 | }␊ |
2761 | else␊ |
2762 | {␊ |
2763 | if (!root->type.isEmpty())␊ |
2764 | {␊ |
2765 | if (root->argList)␊ |
2766 | {␊ |
2767 | def=root->type+" "+qualScope+scopeSeparator+name;␊ |
2768 | }␊ |
2769 | else␊ |
2770 | {␊ |
2771 | def=root->type+" "+qualScope+scopeSeparator+name+root->args;␊ |
2772 | }␊ |
2773 | }␊ |
2774 | else␊ |
2775 | {␊ |
2776 | if (root->argList)␊ |
2777 | {␊ |
2778 | def=qualScope+scopeSeparator+name;␊ |
2779 | }␊ |
2780 | else␊ |
2781 | {␊ |
2782 | def=qualScope+scopeSeparator+name+root->args;␊ |
2783 | }␊ |
2784 | }␊ |
2785 | }␊ |
2786 | if (def.left(7)=="friend ") def=def.right(def.length()-7);␊ |
2787 | md->setDefinition(def);␊ |
2788 | md->enableCallGraph(root->callGraph);␊ |
2789 | md->enableCallerGraph(root->callerGraph);␊ |
2790 | ␊ |
2791 | Debug::print(Debug::Functions,0,␊ |
2792 | " Func Member:\n"␊ |
2793 | " `%s' `%s'::`%s' `%s' proto=%d\n"␊ |
2794 | " def=`%s'\n",␊ |
2795 | root->type.data(),␊ |
2796 | qualScope.data(),␊ |
2797 | rname.data(),␊ |
2798 | root->args.data(),␊ |
2799 | root->proto,␊ |
2800 | def.data()␊ |
2801 | );␊ |
2802 | ␊ |
2803 | // add member to the global list of all members␊ |
2804 | //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());␊ |
2805 | MemberName *mn;␊ |
2806 | if ((mn=Doxygen::memberNameSDict->find(name)))␊ |
2807 | {␊ |
2808 | mn->append(md);␊ |
2809 | }␊ |
2810 | else␊ |
2811 | {␊ |
2812 | mn = new MemberName(name);␊ |
2813 | mn->append(md);␊ |
2814 | Doxygen::memberNameSDict->append(name,mn);␊ |
2815 | }␊ |
2816 | ␊ |
2817 | // add member to the class cd␊ |
2818 | cd->insertMember(md);␊ |
2819 | // add file to list of used files␊ |
2820 | cd->insertUsedFile(root->fileName);␊ |
2821 | ␊ |
2822 | addMemberToGroups(root,md);␊ |
2823 | rootNav->changeSection(Entry::EMPTY_SEC);␊ |
2824 | md->setRefItems(root->sli);␊ |
2825 | }␊ |
2826 | ␊ |
2827 | ␊ |
2828 | static void buildFunctionList(EntryNav *rootNav)␊ |
2829 | {␊ |
2830 | if (rootNav->section()==Entry::FUNCTION_SEC)␊ |
2831 | {␊ |
2832 | rootNav->loadEntry(g_storage);␊ |
2833 | Entry *root = rootNav->entry();␊ |
2834 | ␊ |
2835 | Debug::print(Debug::Functions,0,␊ |
2836 | "FUNCTION_SEC:\n"␊ |
2837 | " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%d proto=%d docFile=%s\n",␊ |
2838 | root->type.data(),␊ |
2839 | rootNav->parent()->name().data(),␊ |
2840 | root->name.data(),␊ |
2841 | root->args.data(),␊ |
2842 | root->relates.data(),␊ |
2843 | root->relatesType,␊ |
2844 | root->fileName.data(),␊ |
2845 | root->startLine,␊ |
2846 | root->bodyLine,␊ |
2847 | root->tArgLists ? (int)root->tArgLists->count() : -1,␊ |
2848 | root->mGrpId,␊ |
2849 | root->spec,␊ |
2850 | root->proto,␊ |
2851 | root->docFile.data()␊ |
2852 | );␊ |
2853 | ␊ |
2854 | bool isFriend=root->type.find("friend ")!=-1;␊ |
2855 | QCString rname = removeRedundantWhiteSpace(root->name);␊ |
2856 | //printf("rname=%s\n",rname.data());␊ |
2857 | ␊ |
2858 | QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);␊ |
2859 | if (!rname.isEmpty() && scope.find('@')==-1)␊ |
2860 | {␊ |
2861 | ClassDef *cd=0;␊ |
2862 | // check if this function's parent is a class␊ |
2863 | scope=stripTemplateSpecifiersFromScope(scope,FALSE);␊ |
2864 | ␊ |
2865 | FileDef *rfd=rootNav->fileDef();␊ |
2866 | ␊ |
2867 | int memIndex=rname.findRev("::");␊ |
2868 | ␊ |
2869 | cd=getClass(scope);␊ |
2870 | if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A␊ |
2871 | {␊ |
2872 | // strip scope from name␊ |
2873 | rname=rname.right(rname.length()-rootNav->parent()->name().length()-2); ␊ |
2874 | }␊ |
2875 | ␊ |
2876 | NamespaceDef *nd = 0;␊ |
2877 | bool isMember=FALSE;␊ |
2878 | if (memIndex!=-1)␊ |
2879 | {␊ |
2880 | int ts=rname.find('<');␊ |
2881 | int te=rname.find('>');␊ |
2882 | if (memIndex>0 && (ts==-1 || te==-1))␊ |
2883 | {␊ |
2884 | // note: the following code was replaced by inMember=TRUE to deal with a ␊ |
2885 | // function rname='X::foo' of class X inside a namespace also called X...␊ |
2886 | // bug id 548175␊ |
2887 | //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));␊ |
2888 | //isMember = nd==0;␊ |
2889 | //if (nd)␊ |
2890 | //{␊ |
2891 | // // strip namespace scope from name␊ |
2892 | // scope=rname.left(memIndex);␊ |
2893 | // rname=rname.right(rname.length()-memIndex-2);␊ |
2894 | //}␊ |
2895 | isMember = TRUE;␊ |
2896 | }␊ |
2897 | else␊ |
2898 | {␊ |
2899 | isMember=memIndex<ts || memIndex>te;␊ |
2900 | }␊ |
2901 | }␊ |
2902 | ␊ |
2903 | static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");␊ |
2904 | if (!rootNav->parent()->name().isEmpty() &&␊ |
2905 | (rootNav->parent()->section() & Entry::COMPOUND_MASK) && ␊ |
2906 | cd &&␊ |
2907 | // do some fuzzy things to exclude function pointers ␊ |
2908 | (root->type.isEmpty() || ␊ |
2909 | (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) || // type contains ..(..* and args not )[.. -> function pointer␊ |
2910 | root->type.find(")(")!=-1 || root->type.find("operator")!=-1 // type contains ..)(.. and not "operator"␊ |
2911 | )␊ |
2912 | )␊ |
2913 | {␊ |
2914 | Debug::print(Debug::Functions,0," --> member %s of class %s!\n",␊ |
2915 | rname.data(),cd->name().data());␊ |
2916 | addMethodToClass(rootNav,cd,rname,isFriend);␊ |
2917 | }␊ |
2918 | else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK) ␊ |
2919 | || rootNav->parent()->section()==Entry::OBJCIMPL_SEC␊ |
2920 | ) &&␊ |
2921 | !isMember &&␊ |
2922 | (root->relates.isEmpty() || root->relatesType == Duplicate) &&␊ |
2923 | root->type.left(7)!="extern " && root->type.left(8)!="typedef " ␊ |
2924 | )␊ |
2925 | // no member => unrelated function ␊ |
2926 | {␊ |
2927 | /* check the uniqueness of the function name in the file.␊ |
2928 | * A file could contain a function prototype and a function definition␊ |
2929 | * or even multiple function prototypes.␊ |
2930 | */␊ |
2931 | bool found=FALSE;␊ |
2932 | MemberName *mn;␊ |
2933 | MemberDef *md=0;␊ |
2934 | if ((mn=Doxygen::functionNameSDict->find(rname)))␊ |
2935 | {␊ |
2936 | Debug::print(Debug::Functions,0," --> function %s already found!\n",rname.data());␊ |
2937 | MemberNameIterator mni(*mn);␊ |
2938 | for (mni.toFirst();(!found && (md=mni.current()));++mni)␊ |
2939 | {␊ |
2940 | NamespaceDef *mnd = md->getNamespaceDef();␊ |
2941 | NamespaceDef *rnd = 0;␊ |
2942 | //printf("root namespace=%s\n",rootNav->parent()->name().data());␊ |
2943 | QCString fullScope = scope;␊ |
2944 | QCString parentScope = rootNav->parent()->name();␊ |
2945 | if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))␊ |
2946 | {␊ |
2947 | if (!scope.isEmpty()) fullScope.prepend("::");␊ |
2948 | fullScope.prepend(parentScope);␊ |
2949 | }␊ |
2950 | //printf("fullScope=%s\n",fullScope.data());␊ |
2951 | rnd = getResolvedNamespace(fullScope);␊ |
2952 | FileDef *mfd = md->getFileDef();␊ |
2953 | QCString nsName,rnsName;␊ |
2954 | if (mnd) nsName = mnd->name().copy();␊ |
2955 | if (rnd) rnsName = rnd->name().copy();␊ |
2956 | //printf("matching arguments for %s%s %s%s\n",␊ |
2957 | // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());␊ |
2958 | LockingPtr<ArgumentList> mdAl = md->argumentList();␊ |
2959 | LockingPtr<ArgumentList> mdTempl = md->templateArguments();␊ |
2960 | ␊ |
2961 | // in case of template functions, we need to check if the␊ |
2962 | // functions have the same number of template parameters␊ |
2963 | bool sameNumTemplateArgs = TRUE;␊ |
2964 | if (mdTempl!=0 && root->tArgLists)␊ |
2965 | {␊ |
2966 | if (mdTempl->count()!=root->tArgLists->getLast()->count())␊ |
2967 | {␊ |
2968 | sameNumTemplateArgs = FALSE;␊ |
2969 | }␊ |
2970 | }␊ |
2971 | if (␊ |
2972 | matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(),␊ |
2973 | rnd ? rnd : Doxygen::globalScope,rfd,root->argList,␊ |
2974 | FALSE) &&␊ |
2975 | sameNumTemplateArgs␊ |
2976 | )␊ |
2977 | {␊ |
2978 | GroupDef *gd=0;␊ |
2979 | if (root->groups->first()!=0)␊ |
2980 | {␊ |
2981 | gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data());␊ |
2982 | }␊ |
2983 | //printf("match!\n");␊ |
2984 | //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());␊ |
2985 | // see if we need to create a new member␊ |
2986 | found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace␊ |
2987 | ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and␊ |
2988 | mfd->absFilePath()==root->fileName // prototype in the same file␊ |
2989 | )␊ |
2990 | );␊ |
2991 | // otherwise, allow a duplicate global member with the same argument list␊ |
2992 | if (!found && gd && gd==md->getGroupDef())␊ |
2993 | {␊ |
2994 | // member is already in the group, so we don't want to add it again.␊ |
2995 | found=TRUE;␊ |
2996 | }␊ |
2997 | ␊ |
2998 | //printf("combining function with prototype found=%d in namespace %s\n",␊ |
2999 | // found,nsName.data());␊ |
3000 | ␊ |
3001 | if (found)␊ |
3002 | {␊ |
3003 | // merge argument lists␊ |
3004 | mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());␊ |
3005 | // merge documentation␊ |
3006 | if (md->documentation().isEmpty() && !root->doc.isEmpty())␊ |
3007 | {␊ |
3008 | ArgumentList *argList = new ArgumentList;␊ |
3009 | stringToArgumentList(root->args,argList);␊ |
3010 | if (root->proto)␊ |
3011 | {␊ |
3012 | //printf("setDeclArgumentList to %p\n",argList);␊ |
3013 | md->setDeclArgumentList(argList);␊ |
3014 | }␊ |
3015 | else␊ |
3016 | {␊ |
3017 | md->setArgumentList(argList);␊ |
3018 | }␊ |
3019 | }␊ |
3020 | ␊ |
3021 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
3022 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
3023 | md->setDocsForDefinition(!root->proto);␊ |
3024 | if (md->getStartBodyLine()!=-1 && md->getStartBodyLine()==-1)␊ |
3025 | {␊ |
3026 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
3027 | md->setBodyDef(rfd);␊ |
3028 | }␊ |
3029 | ␊ |
3030 | if (md->briefDescription().isEmpty() && !root->brief.isEmpty())␊ |
3031 | {␊ |
3032 | md->setArgsString(root->args);␊ |
3033 | }␊ |
3034 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
3035 | ␊ |
3036 | md->addSectionsToDefinition(root->anchors);␊ |
3037 | ␊ |
3038 | md->enableCallGraph(md->hasCallGraph() || root->callGraph);␊ |
3039 | md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);␊ |
3040 | ␊ |
3041 | // merge ingroup specifiers␊ |
3042 | if (md->getGroupDef()==0 && root->groups->first()!=0)␊ |
3043 | {␊ |
3044 | addMemberToGroups(root,md);␊ |
3045 | }␊ |
3046 | else if (md->getGroupDef()!=0 && root->groups->count()==0)␊ |
3047 | {␊ |
3048 | //printf("existing member is grouped, new member not\n");␊ |
3049 | root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));␊ |
3050 | }␊ |
3051 | else if (md->getGroupDef()!=0 && root->groups->first()!=0)␊ |
3052 | {␊ |
3053 | //printf("both members are grouped\n");␊ |
3054 | }␊ |
3055 | ␊ |
3056 | // if md is a declaration and root is the corresponding␊ |
3057 | // definition, then turn md into a definition.␊ |
3058 | if (md->isPrototype() && !root->proto)␊ |
3059 | {␊ |
3060 | md->setPrototype(FALSE);␊ |
3061 | }␊ |
3062 | }␊ |
3063 | }␊ |
3064 | }␊ |
3065 | }␊ |
3066 | if (!found) /* global function is unique with respect to the file */␊ |
3067 | {␊ |
3068 | Debug::print(Debug::Functions,0," --> new function %s found!\n",rname.data());␊ |
3069 | //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",␊ |
3070 | // root->type.data(),rname.data(),root->args.data(),root->bodyLine);␊ |
3071 | ␊ |
3072 | // new global function␊ |
3073 | ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0;␊ |
3074 | QCString name=removeRedundantWhiteSpace(rname);␊ |
3075 | md=new MemberDef(␊ |
3076 | root->fileName,root->startLine,␊ |
3077 | root->type,name,root->args,root->exception,␊ |
3078 | root->protection,root->virt,root->stat,Member,␊ |
3079 | MemberDef::Function,tArgList,root->argList);␊ |
3080 | ␊ |
3081 | md->setTagInfo(rootNav->tagInfo());␊ |
3082 | //md->setDefFile(root->fileName);␊ |
3083 | //md->setDefLine(root->startLine);␊ |
3084 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
3085 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
3086 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
3087 | md->setPrototype(root->proto);␊ |
3088 | md->setDocsForDefinition(!root->proto);␊ |
3089 | md->setTypeConstraints(root->typeConstr);␊ |
3090 | //md->setBody(root->body);␊ |
3091 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
3092 | FileDef *fd=rootNav->fileDef();␊ |
3093 | md->setBodyDef(fd);␊ |
3094 | md->addSectionsToDefinition(root->anchors);␊ |
3095 | md->setMemberSpecifiers(root->spec);␊ |
3096 | md->setMemberGroupId(root->mGrpId);␊ |
3097 | ␊ |
3098 | // see if the function is inside a namespace that was not part of␊ |
3099 | // the name already (in that case nd should be non-zero already)␊ |
3100 | if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )␊ |
3101 | {␊ |
3102 | //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());␊ |
3103 | QCString nscope=rootNav->parent()->name();␊ |
3104 | if (!nscope.isEmpty())␊ |
3105 | {␊ |
3106 | nd = getResolvedNamespace(nscope);␊ |
3107 | }␊ |
3108 | }␊ |
3109 | ␊ |
3110 | if (!scope.isEmpty())␊ |
3111 | {␊ |
3112 | if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))␊ |
3113 | {␊ |
3114 | scope = substitute(scope,"::",".")+".";␊ |
3115 | }␊ |
3116 | else␊ |
3117 | {␊ |
3118 | scope+="::";␊ |
3119 | }␊ |
3120 | }␊ |
3121 | ␊ |
3122 | QCString def;␊ |
3123 | if (!root->type.isEmpty())␊ |
3124 | {␊ |
3125 | if (root->argList)␊ |
3126 | {␊ |
3127 | def=root->type+" "+scope+name;␊ |
3128 | }␊ |
3129 | else␊ |
3130 | {␊ |
3131 | def=root->type+" "+scope+name+root->args;␊ |
3132 | }␊ |
3133 | }␊ |
3134 | else␊ |
3135 | {␊ |
3136 | if (root->argList)␊ |
3137 | {␊ |
3138 | def=scope+name.copy();␊ |
3139 | }␊ |
3140 | else␊ |
3141 | {␊ |
3142 | def=scope+name+root->args;␊ |
3143 | }␊ |
3144 | }␊ |
3145 | Debug::print(Debug::Functions,0,␊ |
3146 | " Global Function:\n"␊ |
3147 | " `%s' `%s'::`%s' `%s' proto=%d\n"␊ |
3148 | " def=`%s'\n",␊ |
3149 | root->type.data(),␊ |
3150 | rootNav->parent()->name().data(),␊ |
3151 | rname.data(),␊ |
3152 | root->args.data(),␊ |
3153 | root->proto,␊ |
3154 | def.data()␊ |
3155 | );␊ |
3156 | md->setDefinition(def);␊ |
3157 | md->enableCallGraph(root->callGraph);␊ |
3158 | md->enableCallerGraph(root->callerGraph);␊ |
3159 | //if (root->mGrpId!=-1) ␊ |
3160 | //{␊ |
3161 | // md->setMemberGroup(memberGroupDict[root->mGrpId]);␊ |
3162 | //}␊ |
3163 | ␊ |
3164 | md->setRefItems(root->sli);␊ |
3165 | if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')␊ |
3166 | {␊ |
3167 | // add member to namespace␊ |
3168 | md->setNamespace(nd);␊ |
3169 | nd->insertMember(md); ␊ |
3170 | }␊ |
3171 | if (fd)␊ |
3172 | {␊ |
3173 | // add member to the file (we do this even if we have already␊ |
3174 | // inserted it into the namespace)␊ |
3175 | md->setFileDef(fd); ␊ |
3176 | fd->insertMember(md);␊ |
3177 | }␊ |
3178 | ␊ |
3179 | // add member to the list of file members␊ |
3180 | //printf("Adding member=%s\n",md->name().data());␊ |
3181 | MemberName *mn;␊ |
3182 | if ((mn=Doxygen::functionNameSDict->find(name)))␊ |
3183 | {␊ |
3184 | mn->append(md);␊ |
3185 | }␊ |
3186 | else ␊ |
3187 | {␊ |
3188 | mn = new MemberName(name);␊ |
3189 | mn->append(md);␊ |
3190 | Doxygen::functionNameSDict->append(name,mn);␊ |
3191 | }␊ |
3192 | addMemberToGroups(root,md);␊ |
3193 | if (root->relatesType == Simple) // if this is a relatesalso command,␊ |
3194 | // allow find Member to pick it up␊ |
3195 | {␊ |
3196 | rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished ␊ |
3197 | // with this entry.␊ |
3198 | ␊ |
3199 | }␊ |
3200 | }␊ |
3201 | else␊ |
3202 | {␊ |
3203 | FileDef *fd=rootNav->fileDef();␊ |
3204 | if (fd)␊ |
3205 | {␊ |
3206 | // add member to the file (we do this even if we have already␊ |
3207 | // inserted it into the namespace)␊ |
3208 | fd->insertMember(md);␊ |
3209 | }␊ |
3210 | }␊ |
3211 | ␊ |
3212 | //printf("unrelated function %d `%s' `%s' `%s'\n",␊ |
3213 | // root->parent->section,root->type.data(),rname.data(),root->args.data());␊ |
3214 | }␊ |
3215 | else␊ |
3216 | {␊ |
3217 | Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data());␊ |
3218 | }␊ |
3219 | }␊ |
3220 | else if (rname.isEmpty())␊ |
3221 | {␊ |
3222 | warn(root->fileName,root->startLine,␊ |
3223 | "warning: Illegal member name found."␊ |
3224 | );␊ |
3225 | }␊ |
3226 | ␊ |
3227 | rootNav->releaseEntry();␊ |
3228 | }␊ |
3229 | RECURSE_ENTRYTREE(buildFunctionList,rootNav);␊ |
3230 | }␊ |
3231 | ␊ |
3232 | //----------------------------------------------------------------------␊ |
3233 | ␊ |
3234 | static void findFriends()␊ |
3235 | {␊ |
3236 | //printf("findFriends()\n");␊ |
3237 | MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);␊ |
3238 | MemberName *fn;␊ |
3239 | for (;(fn=fnli.current());++fnli) // for each global function name␊ |
3240 | {␊ |
3241 | //printf("Function name=`%s'\n",fn->memberName());␊ |
3242 | MemberName *mn;␊ |
3243 | if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))␊ |
3244 | { // there are members with the same name␊ |
3245 | //printf("Function name is also a member name\n");␊ |
3246 | MemberNameIterator fni(*fn);␊ |
3247 | MemberDef *fmd;␊ |
3248 | for (;(fmd=fni.current());++fni) // for each function with that name␊ |
3249 | {␊ |
3250 | MemberNameIterator mni(*mn);␊ |
3251 | MemberDef *mmd;␊ |
3252 | for (;(mmd=mni.current());++mni) // for each member with that name␊ |
3253 | {␊ |
3254 | //printf("Checking for matching arguments ␊ |
3255 | // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",␊ |
3256 | // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());␊ |
3257 | LockingPtr<ArgumentList> mmdAl = mmd->argumentList();␊ |
3258 | LockingPtr<ArgumentList> fmdAl = fmd->argumentList();␊ |
3259 | if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&␊ |
3260 | matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(),␊ |
3261 | fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(),␊ |
3262 | TRUE␊ |
3263 | )␊ |
3264 | ␊ |
3265 | ) // if the member is related and the arguments match then the ␊ |
3266 | // function is actually a friend.␊ |
3267 | {␊ |
3268 | mergeArguments(mmdAl.pointer(),fmdAl.pointer());␊ |
3269 | if (!fmd->documentation().isEmpty())␊ |
3270 | {␊ |
3271 | mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());␊ |
3272 | }␊ |
3273 | else if (!mmd->documentation().isEmpty())␊ |
3274 | {␊ |
3275 | fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());␊ |
3276 | }␊ |
3277 | if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())␊ |
3278 | {␊ |
3279 | mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());␊ |
3280 | }␊ |
3281 | else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())␊ |
3282 | {␊ |
3283 | fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());␊ |
3284 | }␊ |
3285 | if (!fmd->inbodyDocumentation().isEmpty())␊ |
3286 | {␊ |
3287 | mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());␊ |
3288 | }␊ |
3289 | else if (!mmd->inbodyDocumentation().isEmpty())␊ |
3290 | {␊ |
3291 | fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());␊ |
3292 | }␊ |
3293 | //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());␊ |
3294 | if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)␊ |
3295 | {␊ |
3296 | mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());␊ |
3297 | mmd->setBodyDef(fmd->getBodyDef());␊ |
3298 | //mmd->setBodyMember(fmd);␊ |
3299 | }␊ |
3300 | else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)␊ |
3301 | {␊ |
3302 | fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());␊ |
3303 | fmd->setBodyDef(mmd->getBodyDef());␊ |
3304 | //fmd->setBodyMember(mmd);␊ |
3305 | }␊ |
3306 | mmd->setDocsForDefinition(fmd->isDocsForDefinition());␊ |
3307 | ␊ |
3308 | mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());␊ |
3309 | mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());␊ |
3310 | fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());␊ |
3311 | fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());␊ |
3312 | }␊ |
3313 | }␊ |
3314 | }␊ |
3315 | }␊ |
3316 | }␊ |
3317 | }␊ |
3318 | ␊ |
3319 | //----------------------------------------------------------------------␊ |
3320 | ␊ |
3321 | static void transferArgumentDocumentation(ArgumentList *decAl,ArgumentList *defAl)␊ |
3322 | {␊ |
3323 | if (decAl && defAl)␊ |
3324 | {␊ |
3325 | ArgumentListIterator decAli(*decAl);␊ |
3326 | ArgumentListIterator defAli(*defAl);␊ |
3327 | Argument *decA,*defA;␊ |
3328 | for (decAli.toFirst(),defAli.toFirst();␊ |
3329 | (decA=decAli.current()) && (defA=defAli.current());␊ |
3330 | ++decAli,++defAli)␊ |
3331 | {␊ |
3332 | //printf("Argument decA->name=%s (doc=%s) defA->name=%s (doc=%s)\n",␊ |
3333 | // decA->name.data(),decA->docs.data(),␊ |
3334 | // defA->name.data(),defA->docs.data()␊ |
3335 | // );␊ |
3336 | if (decA->docs.isEmpty() && !defA->docs.isEmpty())␊ |
3337 | {␊ |
3338 | decA->docs = defA->docs.copy();␊ |
3339 | }␊ |
3340 | else if (defA->docs.isEmpty() && !decA->docs.isEmpty())␊ |
3341 | {␊ |
3342 | defA->docs = decA->docs.copy();␊ |
3343 | }␊ |
3344 | }␊ |
3345 | }␊ |
3346 | }␊ |
3347 | ␊ |
3348 | static void transferFunctionDocumentation()␊ |
3349 | {␊ |
3350 | //printf("---- transferFunctionDocumentation()\n");␊ |
3351 | ␊ |
3352 | // find matching function declaration and definitions.␊ |
3353 | MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);␊ |
3354 | MemberName *mn;␊ |
3355 | for (;(mn=mnli.current());++mnli)␊ |
3356 | {␊ |
3357 | //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());␊ |
3358 | MemberDef *mdef=0,*mdec=0;␊ |
3359 | MemberNameIterator mni1(*mn);␊ |
3360 | /* find a matching function declaration and definition for this function */␊ |
3361 | for (;(mdec=mni1.current());++mni1)␊ |
3362 | {␊ |
3363 | //printf("mdec=%s isPrototype()=%d\n",mdec->name().data(),mdec->isPrototype());␊ |
3364 | if (mdec->isPrototype() ||␊ |
3365 | (mdec->isVariable() && mdec->isExternal()) ␊ |
3366 | )␊ |
3367 | {␊ |
3368 | MemberNameIterator mni2(*mn);␊ |
3369 | for (;(mdef=mni2.current());++mni2)␊ |
3370 | {␊ |
3371 | if (␊ |
3372 | (mdef->isFunction() && !mdef->isStatic() && !mdef->isPrototype()) ||␊ |
3373 | (mdef->isVariable() && !mdef->isExternal() && !mdef->isStatic())␊ |
3374 | )␊ |
3375 | {␊ |
3376 | //printf("mdef=(%p,%s) mdec=(%p,%s)\n",␊ |
3377 | // mdef, mdef ? mdef->name().data() : "",␊ |
3378 | // mdec, mdec ? mdec->name().data() : "");␊ |
3379 | ␊ |
3380 | LockingPtr<ArgumentList> mdefAl = mdef->argumentList();␊ |
3381 | LockingPtr<ArgumentList> mdecAl = mdec->argumentList();␊ |
3382 | if (matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),␊ |
3383 | mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),␊ |
3384 | TRUE␊ |
3385 | )␊ |
3386 | ) /* match found */␊ |
3387 | {␊ |
3388 | //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n",␊ |
3389 | // mn->memberName(),␊ |
3390 | // mdef->getFileDef()->name().data(),mdef->documentation().data(),␊ |
3391 | // mdec->getFileDef()->name().data(),mdec->documentation().data()␊ |
3392 | // );␊ |
3393 | ␊ |
3394 | // first merge argument documentation␊ |
3395 | transferArgumentDocumentation(mdecAl.pointer(),mdefAl.pointer());␊ |
3396 | ␊ |
3397 | /* copy documentation between function definition and declaration */␊ |
3398 | if (!mdec->briefDescription().isEmpty())␊ |
3399 | {␊ |
3400 | mdef->setBriefDescription(mdec->briefDescription(),mdec->briefFile(),mdec->briefLine());␊ |
3401 | }␊ |
3402 | else if (!mdef->briefDescription().isEmpty())␊ |
3403 | {␊ |
3404 | mdec->setBriefDescription(mdef->briefDescription(),mdef->briefFile(),mdef->briefLine());␊ |
3405 | }␊ |
3406 | if (!mdef->documentation().isEmpty())␊ |
3407 | {␊ |
3408 | //printf("transfering docs mdef->mdec (%s->%s)\n",mdef->argsString(),mdec->argsString());␊ |
3409 | mdec->setDocumentation(mdef->documentation(),mdef->docFile(),mdef->docLine());␊ |
3410 | mdec->setDocsForDefinition(mdef->isDocsForDefinition());␊ |
3411 | if (mdefAl!=0)␊ |
3412 | {␊ |
3413 | ArgumentList *mdefAlComb = new ArgumentList;␊ |
3414 | stringToArgumentList(mdef->argsString(),mdefAlComb);␊ |
3415 | transferArgumentDocumentation(mdefAl.pointer(),mdefAlComb);␊ |
3416 | mdec->setArgumentList(mdefAlComb);␊ |
3417 | }␊ |
3418 | }␊ |
3419 | else if (!mdec->documentation().isEmpty())␊ |
3420 | {␊ |
3421 | //printf("transfering docs mdec->mdef (%s->%s)\n",mdec->argsString(),mdef->argsString());␊ |
3422 | mdef->setDocumentation(mdec->documentation(),mdec->docFile(),mdec->docLine());␊ |
3423 | mdef->setDocsForDefinition(mdec->isDocsForDefinition());␊ |
3424 | if (mdecAl!=0)␊ |
3425 | {␊ |
3426 | ArgumentList *mdecAlComb = new ArgumentList;␊ |
3427 | stringToArgumentList(mdec->argsString(),mdecAlComb);␊ |
3428 | transferArgumentDocumentation(mdecAl.pointer(),mdecAlComb);␊ |
3429 | mdef->setDeclArgumentList(mdecAlComb);␊ |
3430 | }␊ |
3431 | }␊ |
3432 | if (!mdef->inbodyDocumentation().isEmpty())␊ |
3433 | {␊ |
3434 | mdec->setInbodyDocumentation(mdef->inbodyDocumentation(),mdef->inbodyFile(),mdef->inbodyLine());␊ |
3435 | }␊ |
3436 | else if (!mdec->inbodyDocumentation().isEmpty())␊ |
3437 | {␊ |
3438 | mdef->setInbodyDocumentation(mdec->inbodyDocumentation(),mdec->inbodyFile(),mdec->inbodyLine());␊ |
3439 | }␊ |
3440 | if (mdec->getStartBodyLine()!=-1 && mdef->getStartBodyLine()==-1)␊ |
3441 | {␊ |
3442 | //printf("body mdec->mdef %d-%d\n",mdec->getStartBodyLine(),mdef->getEndBodyLine());␊ |
3443 | mdef->setBodySegment(mdec->getStartBodyLine(),mdec->getEndBodyLine());␊ |
3444 | mdef->setBodyDef(mdec->getBodyDef());␊ |
3445 | //mdef->setBodyMember(mdec);␊ |
3446 | }␊ |
3447 | else if (mdef->getStartBodyLine()!=-1 && mdec->getStartBodyLine()==-1)␊ |
3448 | {␊ |
3449 | //printf("body mdef->mdec %d-%d\n",mdef->getStartBodyLine(),mdec->getEndBodyLine());␊ |
3450 | mdec->setBodySegment(mdef->getStartBodyLine(),mdef->getEndBodyLine());␊ |
3451 | mdec->setBodyDef(mdef->getBodyDef());␊ |
3452 | //mdec->setBodyMember(mdef);␊ |
3453 | }␊ |
3454 | mdec->mergeMemberSpecifiers(mdef->getMemberSpecifiers());␊ |
3455 | mdef->mergeMemberSpecifiers(mdec->getMemberSpecifiers());␊ |
3456 | ␊ |
3457 | ␊ |
3458 | // copy group info.␊ |
3459 | if (mdec->getGroupDef()==0 && mdef->getGroupDef()!=0)␊ |
3460 | {␊ |
3461 | mdec->setGroupDef(mdef->getGroupDef(),␊ |
3462 | mdef->getGroupPri(),␊ |
3463 | mdef->docFile(),␊ |
3464 | mdef->docLine(),␊ |
3465 | mdef->hasDocumentation(),␊ |
3466 | mdef␊ |
3467 | );␊ |
3468 | }␊ |
3469 | else if (mdef->getGroupDef()==0 && mdec->getGroupDef()!=0)␊ |
3470 | {␊ |
3471 | mdef->setGroupDef(mdec->getGroupDef(),␊ |
3472 | mdec->getGroupPri(),␊ |
3473 | mdec->docFile(),␊ |
3474 | mdec->docLine(),␊ |
3475 | mdec->hasDocumentation(),␊ |
3476 | mdec␊ |
3477 | );␊ |
3478 | }␊ |
3479 | ␊ |
3480 | ␊ |
3481 | mdec->mergeRefItems(mdef);␊ |
3482 | mdef->mergeRefItems(mdec);␊ |
3483 | ␊ |
3484 | mdef->setMemberDeclaration(mdec);␊ |
3485 | mdec->setMemberDefinition(mdef);␊ |
3486 | ␊ |
3487 | mdef->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());␊ |
3488 | mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());␊ |
3489 | mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());␊ |
3490 | mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());␊ |
3491 | }␊ |
3492 | }␊ |
3493 | }␊ |
3494 | }␊ |
3495 | }␊ |
3496 | }␊ |
3497 | }␊ |
3498 | ␊ |
3499 | //----------------------------------------------------------------------␊ |
3500 | ␊ |
3501 | static void transferFunctionReferences()␊ |
3502 | {␊ |
3503 | MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);␊ |
3504 | MemberName *mn;␊ |
3505 | for (;(mn=mnli.current());++mnli)␊ |
3506 | {␊ |
3507 | MemberDef *md,*mdef=0,*mdec=0;␊ |
3508 | MemberNameIterator mni(*mn);␊ |
3509 | /* find a matching function declaration and definition for this function */␊ |
3510 | for (;(md=mni.current());++mni)␊ |
3511 | {␊ |
3512 | if (md->isPrototype()) ␊ |
3513 | mdec=md;␊ |
3514 | else if (md->isVariable() && md->isExternal()) ␊ |
3515 | mdec=md;␊ |
3516 | ␊ |
3517 | if (md->isFunction() && !md->isStatic() && !md->isPrototype()) ␊ |
3518 | mdef=md;␊ |
3519 | else if (md->isVariable() && !md->isExternal() && !md->isStatic())␊ |
3520 | mdef=md;␊ |
3521 | }␊ |
3522 | if (mdef && mdec)␊ |
3523 | {␊ |
3524 | LockingPtr<ArgumentList> mdefAl = mdef->argumentList();␊ |
3525 | LockingPtr<ArgumentList> mdecAl = mdec->argumentList();␊ |
3526 | if (␊ |
3527 | matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),␊ |
3528 | mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),␊ |
3529 | TRUE␊ |
3530 | )␊ |
3531 | ) /* match found */␊ |
3532 | {␊ |
3533 | LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers();␊ |
3534 | LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers();␊ |
3535 | if (defDict!=0)␊ |
3536 | {␊ |
3537 | MemberSDict::Iterator msdi(*defDict);␊ |
3538 | MemberDef *rmd;␊ |
3539 | for (msdi.toFirst();(rmd=msdi.current());++msdi)␊ |
3540 | {␊ |
3541 | if (decDict==0 || decDict->find(rmd->name())==0)␊ |
3542 | {␊ |
3543 | mdec->addSourceReferences(rmd);␊ |
3544 | }␊ |
3545 | }␊ |
3546 | }␊ |
3547 | if (decDict!=0)␊ |
3548 | {␊ |
3549 | MemberSDict::Iterator msdi(*decDict);␊ |
3550 | MemberDef *rmd;␊ |
3551 | for (msdi.toFirst();(rmd=msdi.current());++msdi)␊ |
3552 | {␊ |
3553 | if (defDict==0 || defDict->find(rmd->name())==0)␊ |
3554 | {␊ |
3555 | mdef->addSourceReferences(rmd);␊ |
3556 | }␊ |
3557 | }␊ |
3558 | }␊ |
3559 | ␊ |
3560 | defDict = mdef->getReferencedByMembers();␊ |
3561 | decDict = mdec->getReferencedByMembers();␊ |
3562 | if (defDict!=0)␊ |
3563 | {␊ |
3564 | MemberSDict::Iterator msdi(*defDict);␊ |
3565 | MemberDef *rmd;␊ |
3566 | for (msdi.toFirst();(rmd=msdi.current());++msdi)␊ |
3567 | {␊ |
3568 | if (decDict==0 || decDict->find(rmd->name())==0)␊ |
3569 | {␊ |
3570 | mdec->addSourceReferencedBy(rmd);␊ |
3571 | }␊ |
3572 | }␊ |
3573 | }␊ |
3574 | if (decDict!=0)␊ |
3575 | {␊ |
3576 | MemberSDict::Iterator msdi(*decDict);␊ |
3577 | MemberDef *rmd;␊ |
3578 | for (msdi.toFirst();(rmd=msdi.current());++msdi)␊ |
3579 | {␊ |
3580 | if (defDict==0 || defDict->find(rmd->name())==0)␊ |
3581 | {␊ |
3582 | mdef->addSourceReferencedBy(rmd);␊ |
3583 | }␊ |
3584 | }␊ |
3585 | }␊ |
3586 | }␊ |
3587 | }␊ |
3588 | }␊ |
3589 | }␊ |
3590 | ␊ |
3591 | //----------------------------------------------------------------------␊ |
3592 | ␊ |
3593 | static void transferRelatedFunctionDocumentation()␊ |
3594 | {␊ |
3595 | // find match between function declaration and definition for ␊ |
3596 | // related functions␊ |
3597 | MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);␊ |
3598 | MemberName *mn;␊ |
3599 | for (mnli.toFirst();(mn=mnli.current());++mnli)␊ |
3600 | {␊ |
3601 | MemberDef *md;␊ |
3602 | MemberNameIterator mni(*mn);␊ |
3603 | /* find a matching function declaration and definition for this function */␊ |
3604 | for (mni.toFirst();(md=mni.current());++mni) // for each global function␊ |
3605 | {␊ |
3606 | //printf(" Function `%s'\n",md->name().data());␊ |
3607 | MemberName *rmn;␊ |
3608 | if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name␊ |
3609 | {␊ |
3610 | //printf(" Member name found\n");␊ |
3611 | MemberDef *rmd;␊ |
3612 | MemberNameIterator rmni(*rmn);␊ |
3613 | for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name␊ |
3614 | {␊ |
3615 | LockingPtr<ArgumentList> mdAl = md->argumentList();␊ |
3616 | LockingPtr<ArgumentList> rmdAl = rmd->argumentList();␊ |
3617 | //printf(" Member found: related=`%d'\n",rmd->isRelated());␊ |
3618 | if ((rmd->isRelated() || rmd->isForeign()) && // related function␊ |
3619 | matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),␊ |
3620 | rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),␊ |
3621 | TRUE␊ |
3622 | )␊ |
3623 | )␊ |
3624 | {␊ |
3625 | //printf(" Found related member `%s'\n",md->name().data());␊ |
3626 | if (rmd->relatedAlso())␊ |
3627 | md->setRelatedAlso(rmd->relatedAlso());␊ |
3628 | else if (rmd->isForeign())␊ |
3629 | md->makeForeign();␊ |
3630 | else␊ |
3631 | md->makeRelated();␊ |
3632 | } ␊ |
3633 | }␊ |
3634 | } ␊ |
3635 | }␊ |
3636 | }␊ |
3637 | }␊ |
3638 | ␊ |
3639 | //----------------------------------------------------------------------␊ |
3640 | ␊ |
3641 | /*! make a dictionary of all template arguments of class cd␊ |
3642 | * that are part of the base class name. ␊ |
3643 | * Example: A template class A with template arguments <R,S,T> ␊ |
3644 | * that inherits from B<T,T,S> will have T and S in the dictionary.␊ |
3645 | */␊ |
3646 | static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)␊ |
3647 | {␊ |
3648 | QDict<int> *templateNames = new QDict<int>(17);␊ |
3649 | templateNames->setAutoDelete(TRUE);␊ |
3650 | static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");␊ |
3651 | if (templateArguments)␊ |
3652 | {␊ |
3653 | ArgumentListIterator ali(*templateArguments);␊ |
3654 | Argument *arg;␊ |
3655 | int count=0;␊ |
3656 | for (ali.toFirst();(arg=ali.current());++ali,count++)␊ |
3657 | {␊ |
3658 | int i,p=0,l;␊ |
3659 | while ((i=re.match(name,p,&l))!=-1)␊ |
3660 | {␊ |
3661 | QCString n = name.mid(i,l);␊ |
3662 | if (n==arg->name)␊ |
3663 | {␊ |
3664 | if (templateNames->find(n)==0)␊ |
3665 | {␊ |
3666 | templateNames->insert(n,new int(count));␊ |
3667 | }␊ |
3668 | }␊ |
3669 | p=i+l;␊ |
3670 | }␊ |
3671 | }␊ |
3672 | }␊ |
3673 | return templateNames;␊ |
3674 | }␊ |
3675 | ␊ |
3676 | /*! Searches a class from within \a context and \a cd and returns its␊ |
3677 | * definition if found (otherwise 0 is returned).␊ |
3678 | */␊ |
3679 | static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)␊ |
3680 | {␊ |
3681 | FileDef *fd=cd->getFileDef();␊ |
3682 | ClassDef *result=0;␊ |
3683 | if (context && cd!=context)␊ |
3684 | {␊ |
3685 | result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);␊ |
3686 | }␊ |
3687 | if (result==0)␊ |
3688 | {␊ |
3689 | result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);␊ |
3690 | }␊ |
3691 | if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)␊ |
3692 | {␊ |
3693 | result = getClass(name);␊ |
3694 | }␊ |
3695 | //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",␊ |
3696 | // name.data(),␊ |
3697 | // context ? context->name().data() : "<none>",␊ |
3698 | // cd ? cd->name().data() : "<none>",␊ |
3699 | // result ? result->name().data() : "<none>",␊ |
3700 | // Doxygen::classSDict.find(name)␊ |
3701 | // );␊ |
3702 | return result;␊ |
3703 | }␊ |
3704 | ␊ |
3705 | enum FindBaseClassRelation_Mode ␊ |
3706 | { ␊ |
3707 | TemplateInstances, ␊ |
3708 | DocumentedOnly, ␊ |
3709 | Undocumented ␊ |
3710 | };␊ |
3711 | ␊ |
3712 | static bool findClassRelation(␊ |
3713 | EntryNav *rootNav,␊ |
3714 | Definition *context,␊ |
3715 | ClassDef *cd,␊ |
3716 | BaseInfo *bi,␊ |
3717 | QDict<int> *templateNames,␊ |
3718 | /*bool insertUndocumented*/␊ |
3719 | FindBaseClassRelation_Mode mode,␊ |
3720 | bool isArtificial␊ |
3721 | );␊ |
3722 | ␊ |
3723 | ␊ |
3724 | static void findUsedClassesForClass(EntryNav *rootNav,␊ |
3725 | Definition *context,␊ |
3726 | ClassDef *masterCd,␊ |
3727 | ClassDef *instanceCd,␊ |
3728 | bool isArtificial,␊ |
3729 | ArgumentList *actualArgs=0,␊ |
3730 | QDict<int> *templateNames=0␊ |
3731 | )␊ |
3732 | {␊ |
3733 | masterCd->visited=TRUE;␊ |
3734 | ArgumentList *formalArgs = masterCd->templateArguments();␊ |
3735 | if (masterCd->memberNameInfoSDict())␊ |
3736 | {␊ |
3737 | MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());␊ |
3738 | MemberNameInfo *mni;␊ |
3739 | for (;(mni=mnili.current());++mnili)␊ |
3740 | {␊ |
3741 | MemberNameInfoIterator mnii(*mni);␊ |
3742 | MemberInfo *mi;␊ |
3743 | for (mnii.toFirst();(mi=mnii.current());++mnii)␊ |
3744 | {␊ |
3745 | MemberDef *md=mi->memberDef;␊ |
3746 | if (md->isVariable()) // for each member variable in this class␊ |
3747 | {␊ |
3748 | //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());␊ |
3749 | QCString type=removeRedundantWhiteSpace(md->typeString());␊ |
3750 | QCString typedefValue = resolveTypeDef(masterCd,type);␊ |
3751 | if (!typedefValue.isEmpty())␊ |
3752 | {␊ |
3753 | type = typedefValue;␊ |
3754 | }␊ |
3755 | int pos=0;␊ |
3756 | QCString usedClassName;␊ |
3757 | QCString templSpec;␊ |
3758 | bool found=FALSE;␊ |
3759 | // the type can contain template variables, replace them if present␊ |
3760 | if (actualArgs)␊ |
3761 | {␊ |
3762 | type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);␊ |
3763 | }␊ |
3764 | ␊ |
3765 | //printf(" template substitution gives=%s\n",type.data());␊ |
3766 | while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1)␊ |
3767 | {␊ |
3768 | // find the type (if any) that matches usedClassName␊ |
3769 | ClassDef *typeCd = getResolvedClass(masterCd,␊ |
3770 | masterCd->getFileDef(),␊ |
3771 | usedClassName,␊ |
3772 | 0,0,␊ |
3773 | FALSE,TRUE␊ |
3774 | );␊ |
3775 | //printf("====> usedClassName=%s -> typeCd=%s\n",␊ |
3776 | // usedClassName.data(),typeCd?typeCd->name().data():"<none>");␊ |
3777 | if (typeCd)␊ |
3778 | {␊ |
3779 | usedClassName = typeCd->name();␊ |
3780 | }␊ |
3781 | ␊ |
3782 | int sp=usedClassName.find('<');␊ |
3783 | if (sp==-1) sp=0;␊ |
3784 | int si=usedClassName.findRev("::",sp);␊ |
3785 | if (si!=-1)␊ |
3786 | {␊ |
3787 | // replace any namespace aliases␊ |
3788 | replaceNamespaceAliases(usedClassName,si);␊ |
3789 | }␊ |
3790 | // add any template arguments to the class␊ |
3791 | QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);␊ |
3792 | //printf(" usedName=%s\n",usedName.data());␊ |
3793 | ␊ |
3794 | bool delTempNames=FALSE;␊ |
3795 | if (templateNames==0)␊ |
3796 | {␊ |
3797 | templateNames = getTemplateArgumentsInName(formalArgs,usedName);␊ |
3798 | delTempNames=TRUE;␊ |
3799 | }␊ |
3800 | BaseInfo bi(usedName,Public,Normal);␊ |
3801 | findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);␊ |
3802 | ␊ |
3803 | if (masterCd->templateArguments())␊ |
3804 | {␊ |
3805 | ArgumentListIterator ali(*masterCd->templateArguments());␊ |
3806 | Argument *arg;␊ |
3807 | int count=0;␊ |
3808 | for (ali.toFirst();(arg=ali.current());++ali,++count)␊ |
3809 | {␊ |
3810 | if (arg->name==usedName) // type is a template argument␊ |
3811 | {␊ |
3812 | found=TRUE;␊ |
3813 | Debug::print(Debug::Classes,0," New used class `%s'\n", usedName.data());␊ |
3814 | ␊ |
3815 | ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);␊ |
3816 | if (usedCd==0)␊ |
3817 | {␊ |
3818 | usedCd = new ClassDef(␊ |
3819 | masterCd->getDefFileName(),masterCd->getDefLine(),␊ |
3820 | usedName,ClassDef::Class);␊ |
3821 | //printf("making %s a template argument!!!\n",usedCd->name().data());␊ |
3822 | usedCd->makeTemplateArgument();␊ |
3823 | usedCd->setUsedOnly(TRUE);␊ |
3824 | Doxygen::hiddenClasses->append(usedName,usedCd);␊ |
3825 | }␊ |
3826 | if (usedCd)␊ |
3827 | {␊ |
3828 | if (isArtificial) usedCd->setArtificial(TRUE);␊ |
3829 | Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", usedCd->name().data());␊ |
3830 | instanceCd->addUsedClass(usedCd,md->name());␊ |
3831 | usedCd->addUsedByClass(instanceCd,md->name());␊ |
3832 | }␊ |
3833 | }␊ |
3834 | }␊ |
3835 | }␊ |
3836 | ␊ |
3837 | if (!found)␊ |
3838 | {␊ |
3839 | ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);␊ |
3840 | //printf("Looking for used class %s: result=%s master=%s\n",␊ |
3841 | // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");␊ |
3842 | ␊ |
3843 | if (usedCd) ␊ |
3844 | {␊ |
3845 | found=TRUE;␊ |
3846 | Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", usedCd->name().data());␊ |
3847 | instanceCd->addUsedClass(usedCd,md->name()); // class exists ␊ |
3848 | usedCd->addUsedByClass(instanceCd,md->name());␊ |
3849 | }␊ |
3850 | }␊ |
3851 | if (delTempNames)␊ |
3852 | {␊ |
3853 | delete templateNames;␊ |
3854 | templateNames=0;␊ |
3855 | }␊ |
3856 | }␊ |
3857 | if (!found && !type.isEmpty()) // used class is not documented in any scope␊ |
3858 | {␊ |
3859 | ClassDef *usedCd = Doxygen::hiddenClasses->find(type);␊ |
3860 | if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))␊ |
3861 | {␊ |
3862 | if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer␊ |
3863 | {␊ |
3864 | type+=md->argsString();␊ |
3865 | }␊ |
3866 | Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data());␊ |
3867 | usedCd = new ClassDef(␊ |
3868 | masterCd->getDefFileName(),masterCd->getDefLine(),␊ |
3869 | type,ClassDef::Class);␊ |
3870 | usedCd->setUsedOnly(TRUE);␊ |
3871 | Doxygen::hiddenClasses->append(type,usedCd);␊ |
3872 | }␊ |
3873 | if (usedCd)␊ |
3874 | {␊ |
3875 | if (isArtificial) usedCd->setArtificial(TRUE);␊ |
3876 | Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", usedCd->name().data());␊ |
3877 | instanceCd->addUsedClass(usedCd,md->name()); ␊ |
3878 | usedCd->addUsedByClass(instanceCd,md->name());␊ |
3879 | }␊ |
3880 | }␊ |
3881 | }␊ |
3882 | }␊ |
3883 | }␊ |
3884 | }␊ |
3885 | else␊ |
3886 | {␊ |
3887 | //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);␊ |
3888 | }␊ |
3889 | }␊ |
3890 | ␊ |
3891 | static void findBaseClassesForClass(␊ |
3892 | EntryNav *rootNav,␊ |
3893 | Definition *context,␊ |
3894 | ClassDef *masterCd,␊ |
3895 | ClassDef *instanceCd,␊ |
3896 | FindBaseClassRelation_Mode mode,␊ |
3897 | bool isArtificial,␊ |
3898 | ArgumentList *actualArgs=0,␊ |
3899 | QDict<int> *templateNames=0␊ |
3900 | )␊ |
3901 | {␊ |
3902 | Entry *root = rootNav->entry();␊ |
3903 | //if (masterCd->visited) return;␊ |
3904 | masterCd->visited=TRUE;␊ |
3905 | // The base class could ofcouse also be a non-nested class␊ |
3906 | ArgumentList *formalArgs = masterCd->templateArguments();␊ |
3907 | QListIterator<BaseInfo> bii(*root->extends);␊ |
3908 | BaseInfo *bi=0;␊ |
3909 | for (bii.toFirst();(bi=bii.current());++bii)␊ |
3910 | {␊ |
3911 | //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",␊ |
3912 | // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);␊ |
3913 | bool delTempNames=FALSE;␊ |
3914 | if (templateNames==0)␊ |
3915 | {␊ |
3916 | templateNames = getTemplateArgumentsInName(formalArgs,bi->name);␊ |
3917 | delTempNames=TRUE;␊ |
3918 | }␊ |
3919 | BaseInfo tbi(bi->name,bi->prot,bi->virt);␊ |
3920 | if (actualArgs) // substitute the formal template arguments of the base class␊ |
3921 | {␊ |
3922 | tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);␊ |
3923 | }␊ |
3924 | //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());␊ |
3925 | ␊ |
3926 | if (mode==DocumentedOnly)␊ |
3927 | {␊ |
3928 | // find a documented base class in the correct scope␊ |
3929 | if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))␊ |
3930 | {␊ |
3931 | if (!Config_getBool("HIDE_UNDOC_RELATIONS"))␊ |
3932 | {␊ |
3933 | // no documented base class -> try to find an undocumented one␊ |
3934 | findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,isArtificial);␊ |
3935 | }␊ |
3936 | }␊ |
3937 | }␊ |
3938 | else if (mode==TemplateInstances)␊ |
3939 | {␊ |
3940 | findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);␊ |
3941 | }␊ |
3942 | if (delTempNames)␊ |
3943 | {␊ |
3944 | delete templateNames;␊ |
3945 | templateNames=0;␊ |
3946 | } ␊ |
3947 | }␊ |
3948 | }␊ |
3949 | ␊ |
3950 | //----------------------------------------------------------------------␊ |
3951 | ␊ |
3952 | static bool findTemplateInstanceRelation(Entry *root,␊ |
3953 | Definition *context,␊ |
3954 | ClassDef *templateClass,const QCString &templSpec,␊ |
3955 | QDict<int> *templateNames,␊ |
3956 | bool isArtificial)␊ |
3957 | {␊ |
3958 | Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",␊ |
3959 | templateClass->name().data(),templSpec.data());␊ |
3960 | //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",␊ |
3961 | // templateClass->name().data(),templSpec.data());␊ |
3962 | //if (templateNames)␊ |
3963 | //{␊ |
3964 | // QDictIterator<int> qdi(*templateNames);␊ |
3965 | // int *tempArgIndex;␊ |
3966 | // for (;(tempArgIndex=qdi.current());++qdi)␊ |
3967 | // {␊ |
3968 | // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);␊ |
3969 | // }␊ |
3970 | //}␊ |
3971 | //printf("\n");␊ |
3972 | ␊ |
3973 | bool existingClass = (templSpec ==␊ |
3974 | tempArgListToString(templateClass->templateArguments())␊ |
3975 | );␊ |
3976 | if (existingClass) return TRUE;␊ |
3977 | ␊ |
3978 | bool freshInstance=FALSE;␊ |
3979 | ClassDef *instanceClass = templateClass->insertTemplateInstance(␊ |
3980 | root->fileName,root->startLine,templSpec,freshInstance);␊ |
3981 | if (isArtificial) instanceClass->setArtificial(TRUE);␊ |
3982 | instanceClass->setLanguage(root->lang);␊ |
3983 | ␊ |
3984 | if (freshInstance)␊ |
3985 | {␊ |
3986 | Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",instanceClass->name().data());␊ |
3987 | Doxygen::classSDict->append(instanceClass->name(),instanceClass);␊ |
3988 | instanceClass->setTemplateBaseClassNames(templateNames);␊ |
3989 | ␊ |
3990 | // search for new template instances caused by base classes of ␊ |
3991 | // instanceClass ␊ |
3992 | EntryNav *templateRootNav = g_classEntries.find(templateClass->name());␊ |
3993 | if (templateRootNav)␊ |
3994 | {␊ |
3995 | bool unloadNeeded=FALSE;␊ |
3996 | Entry *templateRoot = templateRootNav->entry();␊ |
3997 | if (templateRoot==0) // not yet loaded␊ |
3998 | {␊ |
3999 | templateRootNav->loadEntry(g_storage);␊ |
4000 | templateRoot = templateRootNav->entry();␊ |
4001 | ASSERT(templateRoot!=0); // now it should really be loaded␊ |
4002 | unloadNeeded=TRUE;␊ |
4003 | }␊ |
4004 | ␊ |
4005 | Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",␊ |
4006 | templateRoot->name.data(),templSpec.data());␊ |
4007 | ArgumentList *templArgs = new ArgumentList;␊ |
4008 | stringToArgumentList(templSpec,templArgs);␊ |
4009 | findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,␊ |
4010 | TemplateInstances,isArtificial,templArgs,templateNames);␊ |
4011 | ␊ |
4012 | findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,␊ |
4013 | isArtificial,templArgs,templateNames);␊ |
4014 | delete templArgs;␊ |
4015 | ␊ |
4016 | if (unloadNeeded) // still cleanup to do␊ |
4017 | {␊ |
4018 | templateRootNav->releaseEntry();␊ |
4019 | }␊ |
4020 | }␊ |
4021 | else␊ |
4022 | {␊ |
4023 | Debug::print(Debug::Classes,0," no template root entry found!\n");␊ |
4024 | // TODO: what happened if we get here?␊ |
4025 | }␊ |
4026 | ␊ |
4027 | //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());␊ |
4028 | //ArgumentList *tl = templateClass->templateArguments();␊ |
4029 | }␊ |
4030 | else␊ |
4031 | {␊ |
4032 | Debug::print(Debug::Classes,0," instance already exists!\n");␊ |
4033 | }␊ |
4034 | return TRUE;␊ |
4035 | }␊ |
4036 | ␊ |
4037 | static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)␊ |
4038 | {␊ |
4039 | QCString n=name;␊ |
4040 | int index=n.find('<');␊ |
4041 | if (index!=-1)␊ |
4042 | {␊ |
4043 | n=n.left(index);␊ |
4044 | }␊ |
4045 | bool result = rightScopeMatch(scope,n);␊ |
4046 | return result;␊ |
4047 | }␊ |
4048 | ␊ |
4049 | /*! Searches for the end of a template in prototype \a s starting from␊ |
4050 | * character position \a startPos. If the end was found the position␊ |
4051 | * of the closing \> is returned, otherwise -1 is returned.␊ |
4052 | *␊ |
4053 | * Handles exotic cases such as ␊ |
4054 | * \code␊ |
4055 | * Class<(id<0)>␊ |
4056 | * Class<bits<<2>␊ |
4057 | * Class<"<">␊ |
4058 | * Class<'<'>␊ |
4059 | * Class<(")<")>␊ |
4060 | * \endcode␊ |
4061 | */␊ |
4062 | static int findEndOfTemplate(const QCString &s,int startPos)␊ |
4063 | {␊ |
4064 | // locate end of template␊ |
4065 | int e=startPos;␊ |
4066 | int brCount=1;␊ |
4067 | int roundCount=0;␊ |
4068 | int len = s.length();␊ |
4069 | bool insideString=FALSE;␊ |
4070 | bool insideChar=FALSE;␊ |
4071 | char pc = 0;␊ |
4072 | while (e<len && brCount!=0)␊ |
4073 | {␊ |
4074 | char c=s.at(e);␊ |
4075 | switch(c)␊ |
4076 | {␊ |
4077 | case '<': ␊ |
4078 | if (!insideString && !insideChar)␊ |
4079 | {␊ |
4080 | if (e<len-1 && s.at(e+1)=='<') ␊ |
4081 | e++; ␊ |
4082 | else if (roundCount==0)␊ |
4083 | brCount++;␊ |
4084 | }␊ |
4085 | break;␊ |
4086 | case '>':␊ |
4087 | if (!insideString && !insideChar)␊ |
4088 | {␊ |
4089 | if (e<len-1 && s.at(e+1)=='>') ␊ |
4090 | e++; ␊ |
4091 | else if (roundCount==0)␊ |
4092 | brCount--;␊ |
4093 | }␊ |
4094 | break;␊ |
4095 | case '(':␊ |
4096 | if (!insideString && !insideChar) ␊ |
4097 | roundCount++;␊ |
4098 | break;␊ |
4099 | case ')':␊ |
4100 | if (!insideString && !insideChar) ␊ |
4101 | roundCount--;␊ |
4102 | break;␊ |
4103 | case '"':␊ |
4104 | if (!insideChar)␊ |
4105 | {␊ |
4106 | if (insideString && pc!='\\') ␊ |
4107 | insideString=FALSE;␊ |
4108 | else␊ |
4109 | insideString=TRUE;␊ |
4110 | }␊ |
4111 | break;␊ |
4112 | case '\'':␊ |
4113 | if (!insideString)␊ |
4114 | {␊ |
4115 | if (insideChar && pc!='\\')␊ |
4116 | insideChar=FALSE;␊ |
4117 | else␊ |
4118 | insideChar=TRUE;␊ |
4119 | }␊ |
4120 | break;␊ |
4121 | }␊ |
4122 | pc = c;␊ |
4123 | e++;␊ |
4124 | }␊ |
4125 | return brCount==0 ? e : -1;␊ |
4126 | }␊ |
4127 | ␊ |
4128 | static bool findClassRelation(␊ |
4129 | EntryNav *rootNav,␊ |
4130 | Definition *context,␊ |
4131 | ClassDef *cd,␊ |
4132 | BaseInfo *bi,␊ |
4133 | QDict<int> *templateNames,␊ |
4134 | FindBaseClassRelation_Mode mode,␊ |
4135 | bool isArtificial␊ |
4136 | )␊ |
4137 | {␊ |
4138 | //printf("findClassRelation(class=%s base=%s templateNames=",␊ |
4139 | // cd->name().data(),bi->name.data());␊ |
4140 | //if (templateNames)␊ |
4141 | //{␊ |
4142 | // QDictIterator<int> qdi(*templateNames);␊ |
4143 | // int *tempArgIndex;␊ |
4144 | // for (;(tempArgIndex=qdi.current());++qdi)␊ |
4145 | // {␊ |
4146 | // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);␊ |
4147 | // }␊ |
4148 | //}␊ |
4149 | //printf("\n");␊ |
4150 | ␊ |
4151 | Entry *root = rootNav->entry();␊ |
4152 | ␊ |
4153 | QCString biName=bi->name;␊ |
4154 | bool explicitGlobalScope=FALSE;␊ |
4155 | //printf("findClassRelation: biName=`%s'\n",biName.data());␊ |
4156 | if (biName.left(2)=="::") // explicit global scope␊ |
4157 | {␊ |
4158 | biName=biName.right(biName.length()-2);␊ |
4159 | explicitGlobalScope=TRUE;␊ |
4160 | }␊ |
4161 | ␊ |
4162 | EntryNav *parentNode=rootNav->parent();␊ |
4163 | bool lastParent=FALSE;␊ |
4164 | do // for each parent scope, starting with the largest scope ␊ |
4165 | // (in case of nested classes)␊ |
4166 | {␊ |
4167 | QCString scopeName= parentNode ? parentNode->name().data() : "";␊ |
4168 | int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();␊ |
4169 | do // try all parent scope prefixes, starting with the largest scope␊ |
4170 | {␊ |
4171 | //printf("scopePrefix=`%s' biName=`%s'\n",␊ |
4172 | // scopeName.left(scopeOffset).data(),biName.data());␊ |
4173 | ␊ |
4174 | QCString baseClassName=biName;␊ |
4175 | if (scopeOffset>0)␊ |
4176 | {␊ |
4177 | baseClassName.prepend(scopeName.left(scopeOffset)+"::");␊ |
4178 | }␊ |
4179 | //QCString stripped;␊ |
4180 | //baseClassName=stripTemplateSpecifiersFromScope␊ |
4181 | // (removeRedundantWhiteSpace(baseClassName),TRUE,␊ |
4182 | // &stripped);␊ |
4183 | MemberDef *baseClassTypeDef=0;␊ |
4184 | QCString templSpec;␊ |
4185 | ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,␊ |
4186 | cd->getFileDef(), ␊ |
4187 | baseClassName,␊ |
4188 | &baseClassTypeDef,␊ |
4189 | &templSpec,␊ |
4190 | mode==Undocumented,␊ |
4191 | TRUE␊ |
4192 | );␊ |
4193 | //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",␊ |
4194 | // baseClassName.data(),baseClass,cd,explicitGlobalScope);␊ |
4195 | //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",␊ |
4196 | // cd ? cd->name().data():"<none>",␊ |
4197 | // baseClassName.data(),␊ |
4198 | // baseClass?baseClass->name().data():"<none>",␊ |
4199 | // templSpec.data()␊ |
4200 | // );␊ |
4201 | //if (baseClassName.left(root->name.length())!=root->name ||␊ |
4202 | // baseClassName.at(root->name.length())!='<'␊ |
4203 | // ) // Check for base class with the same name.␊ |
4204 | // // If found then look in the outer scope for a match␊ |
4205 | // // and prevent recursion.␊ |
4206 | if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope)␊ |
4207 | {␊ |
4208 | Debug::print(␊ |
4209 | Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",␊ |
4210 | baseClassName.data(),␊ |
4211 | rootNav->name().data(),␊ |
4212 | (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),␊ |
4213 | (bi->virt==Normal)?"normal":"virtual",␊ |
4214 | templSpec.data()␊ |
4215 | );␊ |
4216 | ␊ |
4217 | int i=baseClassName.find('<');␊ |
4218 | int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);␊ |
4219 | if (si==-1) si=0;␊ |
4220 | if (baseClass==0 && i!=-1) ␊ |
4221 | // base class has template specifiers␊ |
4222 | {␊ |
4223 | // TODO: here we should try to find the correct template specialization␊ |
4224 | // but for now, we only look for the unspecializated base class.␊ |
4225 | int e=findEndOfTemplate(baseClassName,i+1);␊ |
4226 | //printf("baseClass==0 i=%d e=%d\n",i,e);␊ |
4227 | if (e!=-1) // end of template was found at e␊ |
4228 | {␊ |
4229 | templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));␊ |
4230 | baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);␊ |
4231 | baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,␊ |
4232 | cd->getFileDef(),␊ |
4233 | baseClassName,␊ |
4234 | &baseClassTypeDef,␊ |
4235 | 0, //&templSpec,␊ |
4236 | mode==Undocumented,␊ |
4237 | TRUE␊ |
4238 | );␊ |
4239 | //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",␊ |
4240 | // baseClass,baseClassName.data(),templSpec.data());␊ |
4241 | }␊ |
4242 | }␊ |
4243 | else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also␊ |
4244 | // know it is a template, so see if␊ |
4245 | // we can also link to the explicit␊ |
4246 | // instance (for instance if a class␊ |
4247 | // derived from a template argument)␊ |
4248 | {␊ |
4249 | //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());␊ |
4250 | ClassDef *templClass=getClass(baseClass->name()+templSpec);␊ |
4251 | if (templClass)␊ |
4252 | {␊ |
4253 | // use the template instance instead of the template base.␊ |
4254 | baseClass = templClass;␊ |
4255 | templSpec.resize(0);␊ |
4256 | }␊ |
4257 | }␊ |
4258 | ␊ |
4259 | //printf("cd=%p baseClass=%p\n",cd,baseClass);␊ |
4260 | bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);␊ |
4261 | //printf("1. found=%d\n",found);␊ |
4262 | if (!found && si!=-1)␊ |
4263 | {␊ |
4264 | QCString tmpTemplSpec;␊ |
4265 | // replace any namespace aliases␊ |
4266 | replaceNamespaceAliases(baseClassName,si);␊ |
4267 | baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,␊ |
4268 | cd->getFileDef(),␊ |
4269 | baseClassName,␊ |
4270 | &baseClassTypeDef,␊ |
4271 | &tmpTemplSpec,␊ |
4272 | mode==Undocumented,␊ |
4273 | TRUE␊ |
4274 | );␊ |
4275 | found=baseClass!=0 && baseClass!=cd;␊ |
4276 | if (found) templSpec = tmpTemplSpec;␊ |
4277 | }␊ |
4278 | //printf("2. found=%d\n",found);␊ |
4279 | ␊ |
4280 | //printf("root->name=%s biName=%s baseClassName=%s\n",␊ |
4281 | // root->name.data(),biName.data(),baseClassName.data());␊ |
4282 | if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix␊ |
4283 | {␊ |
4284 | baseClassName+="-g";␊ |
4285 | templSpec.resize(0);␊ |
4286 | }␊ |
4287 | ␊ |
4288 | if (!found)␊ |
4289 | {␊ |
4290 | baseClass=findClassWithinClassContext(context,cd,baseClassName);␊ |
4291 | //printf("findClassWithinClassContext(%s,%s)=%p\n",␊ |
4292 | // cd->name().data(),baseClassName.data(),baseClass);␊ |
4293 | found = baseClass!=0 && baseClass!=cd;␊ |
4294 | ␊ |
4295 | }␊ |
4296 | if (!found)␊ |
4297 | {␊ |
4298 | // for PHP the "use A\B as C" construct map class C to A::B, so we lookup␊ |
4299 | // the class name also in the alias mapping.␊ |
4300 | QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];␊ |
4301 | if (aliasName) // see if it is indeed a class.␊ |
4302 | {␊ |
4303 | baseClass=getClass(*aliasName);␊ |
4304 | found = baseClass!=0 && baseClass!=cd;␊ |
4305 | }␊ |
4306 | }␊ |
4307 | bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;␊ |
4308 | // make templSpec canonical␊ |
4309 | // warning: the following line doesn't work for Mixin classes (see bug 560623)␊ |
4310 | // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);␊ |
4311 | ␊ |
4312 | //printf("3. found=%d\n",found);␊ |
4313 | if (found)␊ |
4314 | {␊ |
4315 | Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());␊ |
4316 | // add base class to this class␊ |
4317 | ␊ |
4318 | // if templSpec is not empty then we should "instantiate"␊ |
4319 | // the template baseClass. A new ClassDef should be created␊ |
4320 | // to represent the instance. To be able to add the (instantiated)␊ |
4321 | // members and documentation of a template class ␊ |
4322 | // (inserted in that template class at a later stage), ␊ |
4323 | // the template should know about its instances. ␊ |
4324 | // the instantiation process, should be done in a recursive way, ␊ |
4325 | // since instantiating a template may introduce new inheritance ␊ |
4326 | // relations.␊ |
4327 | if (!templSpec.isEmpty() && mode==TemplateInstances)␊ |
4328 | {␊ |
4329 | // if baseClass is actually a typedef then we should not␊ |
4330 | // instantiate it, since typedefs are in a different namespace␊ |
4331 | // see bug531637 for an example where this would otherwise hang␊ |
4332 | // doxygen␊ |
4333 | if (baseClassTypeDef==0)␊ |
4334 | {␊ |
4335 | //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);␊ |
4336 | findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);␊ |
4337 | }␊ |
4338 | }␊ |
4339 | else if (mode==DocumentedOnly || mode==Undocumented)␊ |
4340 | {␊ |
4341 | //printf(" => insert base class\n");␊ |
4342 | QCString usedName;␊ |
4343 | if (baseClassTypeDef || cd->isCSharp()) ␊ |
4344 | {␊ |
4345 | usedName=biName;␊ |
4346 | //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());␊ |
4347 | }␊ |
4348 | if (Config_getBool("SIP_SUPPORT")) bi->prot=Public;␊ |
4349 | cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);␊ |
4350 | // add this class as super class to the base class␊ |
4351 | baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);␊ |
4352 | }␊ |
4353 | return TRUE;␊ |
4354 | }␊ |
4355 | else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))␊ |
4356 | {␊ |
4357 | Debug::print(Debug::Classes,0,␊ |
4358 | " New undocumented base class `%s' baseClassName=%s\n",␊ |
4359 | biName.data(),baseClassName.data()␊ |
4360 | );␊ |
4361 | baseClass=0;␊ |
4362 | if (isATemplateArgument)␊ |
4363 | {␊ |
4364 | baseClass=Doxygen::hiddenClasses->find(baseClassName);␊ |
4365 | if (baseClass==0)␊ |
4366 | {␊ |
4367 | baseClass=new ClassDef(root->fileName,root->startLine,␊ |
4368 | baseClassName,ClassDef::Class);␊ |
4369 | Doxygen::hiddenClasses->append(baseClassName,baseClass);␊ |
4370 | if (isArtificial) baseClass->setArtificial(TRUE);␊ |
4371 | }␊ |
4372 | }␊ |
4373 | else␊ |
4374 | {␊ |
4375 | baseClass=Doxygen::classSDict->find(baseClassName);␊ |
4376 | //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",␊ |
4377 | // baseClassName.data(),baseClass,biName.data(),templSpec.data());␊ |
4378 | if (baseClass==0)␊ |
4379 | {␊ |
4380 | baseClass=new ClassDef(root->fileName,root->startLine,␊ |
4381 | baseClassName,ClassDef::Class);␊ |
4382 | Doxygen::classSDict->append(baseClassName,baseClass);␊ |
4383 | if (isArtificial) baseClass->setArtificial(TRUE);␊ |
4384 | }␊ |
4385 | }␊ |
4386 | // add base class to this class␊ |
4387 | cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);␊ |
4388 | // add this class as super class to the base class␊ |
4389 | baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);␊ |
4390 | // the undocumented base was found in this file␊ |
4391 | baseClass->insertUsedFile(root->fileName);␊ |
4392 | baseClass->setOuterScope(Doxygen::globalScope);␊ |
4393 | return TRUE;␊ |
4394 | }␊ |
4395 | else␊ |
4396 | {␊ |
4397 | Debug::print(Debug::Classes,0," Base class `%s' not found\n",biName.data());␊ |
4398 | }␊ |
4399 | }␊ |
4400 | else␊ |
4401 | {␊ |
4402 | if (mode!=TemplateInstances)␊ |
4403 | {␊ |
4404 | warn(root->fileName,root->startLine,␊ |
4405 | "Detected potential recursive class relation "␊ |
4406 | "between class %s and base class %s!\n",␊ |
4407 | root->name.data(),baseClassName.data()␊ |
4408 | );␊ |
4409 | }␊ |
4410 | // for mode==TemplateInstance this case is quite common and␊ |
4411 | // indicates a relation between a template class and a template ␊ |
4412 | // instance with the same name.␊ |
4413 | }␊ |
4414 | if (scopeOffset==0)␊ |
4415 | {␊ |
4416 | scopeOffset=-1;␊ |
4417 | }␊ |
4418 | else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)␊ |
4419 | {␊ |
4420 | scopeOffset=0;␊ |
4421 | }␊ |
4422 | //printf("new scopeOffset=`%d'",scopeOffset);␊ |
4423 | } while (scopeOffset>=0);␊ |
4424 | ␊ |
4425 | if (parentNode==0)␊ |
4426 | {␊ |
4427 | lastParent=TRUE;␊ |
4428 | }␊ |
4429 | else␊ |
4430 | {␊ |
4431 | parentNode=parentNode->parent();␊ |
4432 | }␊ |
4433 | } while (lastParent);␊ |
4434 | ␊ |
4435 | return FALSE;␊ |
4436 | }␊ |
4437 | ␊ |
4438 | //----------------------------------------------------------------------␊ |
4439 | // Computes the base and super classes for each class in the tree␊ |
4440 | ␊ |
4441 | static bool isClassSection(EntryNav *rootNav)␊ |
4442 | {␊ |
4443 | if ( !rootNav->name().isEmpty() )␊ |
4444 | {␊ |
4445 | if (rootNav->section() & Entry::COMPOUND_MASK)␊ |
4446 | // is it a compound (class, struct, union, interface ...)␊ |
4447 | {␊ |
4448 | return TRUE;␊ |
4449 | }␊ |
4450 | else if (rootNav->section() & Entry::COMPOUNDDOC_MASK) ␊ |
4451 | // is it a documentation block with inheritance info.␊ |
4452 | {␊ |
4453 | rootNav->loadEntry(g_storage);␊ |
4454 | Entry *root = rootNav->entry();␊ |
4455 | bool extends = root->extends->count()>0;␊ |
4456 | rootNav->releaseEntry(); ␊ |
4457 | if (extends) return TRUE;␊ |
4458 | }␊ |
4459 | }␊ |
4460 | return FALSE;␊ |
4461 | }␊ |
4462 | ␊ |
4463 | ␊ |
4464 | /*! Builds a dictionary of all entry nodes in the tree starting with \a root␊ |
4465 | */␊ |
4466 | static void findClassEntries(EntryNav *rootNav)␊ |
4467 | {␊ |
4468 | if (isClassSection(rootNav))␊ |
4469 | {␊ |
4470 | g_classEntries.insert(rootNav->name(),rootNav);␊ |
4471 | }␊ |
4472 | RECURSE_ENTRYTREE(findClassEntries,rootNav);␊ |
4473 | }␊ |
4474 | ␊ |
4475 | /*! Using the dictionary build by findClassEntries(), this ␊ |
4476 | * function will look for additional template specialization that␊ |
4477 | * exists as inheritance relations only. These instances will be␊ |
4478 | * added to the template they are derived from.␊ |
4479 | */␊ |
4480 | static void findInheritedTemplateInstances()␊ |
4481 | {␊ |
4482 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
4483 | for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;␊ |
4484 | QDictIterator<EntryNav> edi(g_classEntries);␊ |
4485 | EntryNav *rootNav;␊ |
4486 | for (;(rootNav=edi.current());++edi)␊ |
4487 | {␊ |
4488 | ClassDef *cd;␊ |
4489 | // strip any anonymous scopes first ␊ |
4490 | QCString bName=stripAnonymousNamespaceScope(rootNav->name());␊ |
4491 | bName=stripTemplateSpecifiersFromScope(bName);␊ |
4492 | Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",bName.data());␊ |
4493 | if ((cd=getClass(bName)))␊ |
4494 | {␊ |
4495 | rootNav->loadEntry(g_storage);␊ |
4496 | //printf("Class %s %d\n",cd->name().data(),root->extends->count());␊ |
4497 | findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);␊ |
4498 | rootNav->releaseEntry();␊ |
4499 | }␊ |
4500 | }␊ |
4501 | }␊ |
4502 | ␊ |
4503 | static void findUsedTemplateInstances()␊ |
4504 | {␊ |
4505 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
4506 | for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;␊ |
4507 | QDictIterator<EntryNav> edi(g_classEntries);␊ |
4508 | EntryNav *rootNav;␊ |
4509 | for (;(rootNav=edi.current());++edi)␊ |
4510 | {␊ |
4511 | ClassDef *cd;␊ |
4512 | // strip any anonymous scopes first ␊ |
4513 | QCString bName=stripAnonymousNamespaceScope(rootNav->name());␊ |
4514 | bName=stripTemplateSpecifiersFromScope(bName);␊ |
4515 | Debug::print(Debug::Classes,0," Usage: Class %s : \n",bName.data());␊ |
4516 | if ((cd=getClass(bName)))␊ |
4517 | {␊ |
4518 | rootNav->loadEntry(g_storage);␊ |
4519 | findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);␊ |
4520 | rootNav->releaseEntry();␊ |
4521 | }␊ |
4522 | }␊ |
4523 | }␊ |
4524 | ␊ |
4525 | static void computeClassRelations()␊ |
4526 | {␊ |
4527 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
4528 | for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;␊ |
4529 | QDictIterator<EntryNav> edi(g_classEntries);␊ |
4530 | EntryNav *rootNav;␊ |
4531 | for (;(rootNav=edi.current());++edi)␊ |
4532 | {␊ |
4533 | ClassDef *cd;␊ |
4534 | ␊ |
4535 | rootNav->loadEntry(g_storage);␊ |
4536 | Entry *root = rootNav->entry();␊ |
4537 | ␊ |
4538 | // strip any anonymous scopes first ␊ |
4539 | QCString bName=stripAnonymousNamespaceScope(rootNav->name());␊ |
4540 | bName=stripTemplateSpecifiersFromScope(bName);␊ |
4541 | Debug::print(Debug::Classes,0," Relations: Class %s : \n",bName.data());␊ |
4542 | if ((cd=getClass(bName)))␊ |
4543 | {␊ |
4544 | findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);␊ |
4545 | }␊ |
4546 | if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && ␊ |
4547 | bName.right(2)!="::")␊ |
4548 | {␊ |
4549 | if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name␊ |
4550 | (guessSection(root->fileName)==Entry::HEADER_SEC || ␊ |
4551 | Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file␊ |
4552 | (root->protection!=Private || Config_getBool("EXTRACT_PRIVATE")) && // hidden by protection␊ |
4553 | !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible␊ |
4554 | )␊ |
4555 | warn_undoc(␊ |
4556 | root->fileName,root->startLine,␊ |
4557 | "warning: Compound %s is not documented.",␊ |
4558 | root->name.data()␊ |
4559 | );␊ |
4560 | }␊ |
4561 | ␊ |
4562 | rootNav->releaseEntry();␊ |
4563 | }␊ |
4564 | }␊ |
4565 | ␊ |
4566 | static void computeTemplateClassRelations()␊ |
4567 | {␊ |
4568 | QDictIterator<EntryNav> edi(g_classEntries);␊ |
4569 | EntryNav *rootNav;␊ |
4570 | for (;(rootNav=edi.current());++edi)␊ |
4571 | {␊ |
4572 | rootNav->loadEntry(g_storage);␊ |
4573 | Entry *root = rootNav->entry();␊ |
4574 | ␊ |
4575 | QCString bName=stripAnonymousNamespaceScope(root->name);␊ |
4576 | bName=stripTemplateSpecifiersFromScope(bName);␊ |
4577 | ClassDef *cd=getClass(bName);␊ |
4578 | // strip any anonymous scopes first ␊ |
4579 | QDict<ClassDef> *templInstances = 0;␊ |
4580 | if (cd && (templInstances=cd->getTemplateInstances()))␊ |
4581 | {␊ |
4582 | Debug::print(Debug::Classes,0," Template class %s : \n",cd->name().data());␊ |
4583 | QDictIterator<ClassDef> tdi(*templInstances);␊ |
4584 | ClassDef *tcd;␊ |
4585 | for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance␊ |
4586 | {␊ |
4587 | Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data());␊ |
4588 | QCString templSpec = tdi.currentKey();␊ |
4589 | ArgumentList *templArgs = new ArgumentList;␊ |
4590 | stringToArgumentList(templSpec,templArgs);␊ |
4591 | QList<BaseInfo> *baseList=root->extends;␊ |
4592 | BaseInfo *bi=baseList->first();␊ |
4593 | while (bi) // for each base class of the template␊ |
4594 | {␊ |
4595 | // check if the base class is a template argument␊ |
4596 | BaseInfo tbi(bi->name,bi->prot,bi->virt);␊ |
4597 | ArgumentList *tl = cd->templateArguments();␊ |
4598 | if (tl)␊ |
4599 | {␊ |
4600 | QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();␊ |
4601 | QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);␊ |
4602 | // for each template name that we inherit from we need to␊ |
4603 | // substitute the formal with the actual arguments␊ |
4604 | QDict<int> *actualTemplateNames = new QDict<int>(17);␊ |
4605 | actualTemplateNames->setAutoDelete(TRUE);␊ |
4606 | QDictIterator<int> qdi(*templateNames);␊ |
4607 | for (qdi.toFirst();qdi.current();++qdi)␊ |
4608 | {␊ |
4609 | int templIndex = *qdi.current();␊ |
4610 | Argument *actArg = 0;␊ |
4611 | if (templIndex<(int)templArgs->count()) ␊ |
4612 | {␊ |
4613 | actArg=templArgs->at(templIndex);␊ |
4614 | }␊ |
4615 | if (actArg!=0 &&␊ |
4616 | baseClassNames!=0 &&␊ |
4617 | baseClassNames->find(actArg->type)!=0 &&␊ |
4618 | actualTemplateNames->find(actArg->type)==0␊ |
4619 | )␊ |
4620 | {␊ |
4621 | actualTemplateNames->insert(actArg->type,new int(templIndex));␊ |
4622 | }␊ |
4623 | }␊ |
4624 | delete templateNames;␊ |
4625 | ␊ |
4626 | tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);␊ |
4627 | // find a documented base class in the correct scope␊ |
4628 | if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))␊ |
4629 | {␊ |
4630 | // no documented base class -> try to find an undocumented one␊ |
4631 | findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE);␊ |
4632 | }␊ |
4633 | delete actualTemplateNames;␊ |
4634 | }␊ |
4635 | bi=baseList->next();␊ |
4636 | }␊ |
4637 | delete templArgs;␊ |
4638 | } // class has no base classes␊ |
4639 | }␊ |
4640 | ␊ |
4641 | rootNav->releaseEntry();␊ |
4642 | }␊ |
4643 | }␊ |
4644 | ␊ |
4645 | //-----------------------------------------------------------------------␊ |
4646 | // compute the references (anchors in HTML) for each function in the file␊ |
4647 | ␊ |
4648 | static void computeMemberReferences()␊ |
4649 | {␊ |
4650 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
4651 | ClassDef *cd=0;␊ |
4652 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
4653 | {␊ |
4654 | cd->computeAnchors();␊ |
4655 | } ␊ |
4656 | FileName *fn=Doxygen::inputNameList->first();␊ |
4657 | while (fn)␊ |
4658 | {␊ |
4659 | FileDef *fd=fn->first();␊ |
4660 | while (fd)␊ |
4661 | {␊ |
4662 | fd->computeAnchors();␊ |
4663 | fd=fn->next();␊ |
4664 | }␊ |
4665 | fn=Doxygen::inputNameList->next();␊ |
4666 | }␊ |
4667 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
4668 | NamespaceDef *nd=0;␊ |
4669 | for (nli.toFirst();(nd=nli.current());++nli)␊ |
4670 | {␊ |
4671 | nd->computeAnchors();␊ |
4672 | }␊ |
4673 | GroupSDict::Iterator gli(*Doxygen::groupSDict);␊ |
4674 | GroupDef *gd;␊ |
4675 | for (gli.toFirst();(gd=gli.current());++gli)␊ |
4676 | {␊ |
4677 | gd->computeAnchors();␊ |
4678 | }␊ |
4679 | }␊ |
4680 | ␊ |
4681 | //----------------------------------------------------------------------␊ |
4682 | ␊ |
4683 | static void addListReferences()␊ |
4684 | {␊ |
4685 | MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);␊ |
4686 | MemberName *mn=0;␊ |
4687 | for (mnli.toFirst();(mn=mnli.current());++mnli)␊ |
4688 | {␊ |
4689 | MemberNameIterator mni(*mn);␊ |
4690 | MemberDef *md=0;␊ |
4691 | for (mni.toFirst();(md=mni.current());++mni)␊ |
4692 | {␊ |
4693 | md->visited=FALSE;␊ |
4694 | }␊ |
4695 | }␊ |
4696 | MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);␊ |
4697 | for (fnli.toFirst();(mn=fnli.current());++fnli)␊ |
4698 | {␊ |
4699 | MemberNameIterator mni(*mn);␊ |
4700 | MemberDef *md=0;␊ |
4701 | for (mni.toFirst();(md=mni.current());++mni)␊ |
4702 | {␊ |
4703 | md->visited=FALSE;␊ |
4704 | }␊ |
4705 | }␊ |
4706 | ␊ |
4707 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
4708 | ClassDef *cd=0;␊ |
4709 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
4710 | {␊ |
4711 | cd->addListReferences();␊ |
4712 | } ␊ |
4713 | FileName *fn=Doxygen::inputNameList->first();␊ |
4714 | while (fn)␊ |
4715 | {␊ |
4716 | FileDef *fd=fn->first();␊ |
4717 | while (fd)␊ |
4718 | {␊ |
4719 | fd->addListReferences();␊ |
4720 | fd=fn->next();␊ |
4721 | }␊ |
4722 | fn=Doxygen::inputNameList->next();␊ |
4723 | }␊ |
4724 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
4725 | NamespaceDef *nd=0;␊ |
4726 | for (nli.toFirst();(nd=nli.current());++nli)␊ |
4727 | {␊ |
4728 | nd->addListReferences();␊ |
4729 | }␊ |
4730 | GroupSDict::Iterator gli(*Doxygen::groupSDict);␊ |
4731 | GroupDef *gd;␊ |
4732 | for (gli.toFirst();(gd=gli.current());++gli)␊ |
4733 | {␊ |
4734 | gd->addListReferences();␊ |
4735 | }␊ |
4736 | PageSDict::Iterator pdi(*Doxygen::pageSDict);␊ |
4737 | PageDef *pd=0;␊ |
4738 | for (pdi.toFirst();(pd=pdi.current());++pdi)␊ |
4739 | {␊ |
4740 | QCString name = pd->getOutputFileBase();␊ |
4741 | if (pd->getGroupDef())␊ |
4742 | {␊ |
4743 | name = pd->getGroupDef()->getOutputFileBase();␊ |
4744 | }␊ |
4745 | {␊ |
4746 | LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems();␊ |
4747 | addRefItem(xrefItems.pointer(),␊ |
4748 | name,␊ |
4749 | theTranslator->trPage(TRUE,TRUE),␊ |
4750 | name,pd->title(),0);␊ |
4751 | }␊ |
4752 | }␊ |
4753 | DirSDict::Iterator ddi(*Doxygen::directories);␊ |
4754 | DirDef *dd = 0;␊ |
4755 | for (ddi.toFirst();(dd=ddi.current());++ddi)␊ |
4756 | {␊ |
4757 | QCString name = dd->getOutputFileBase();␊ |
4758 | //if (dd->getGroupDef())␊ |
4759 | //{␊ |
4760 | // name = dd->getGroupDef()->getOutputFileBase();␊ |
4761 | //}␊ |
4762 | LockingPtr< QList<ListItemInfo> > xrefItems = dd->xrefListItems();␊ |
4763 | addRefItem(xrefItems.pointer(),␊ |
4764 | name,␊ |
4765 | theTranslator->trDir(TRUE,TRUE),␊ |
4766 | name,dd->displayName(),0);␊ |
4767 | }␊ |
4768 | }␊ |
4769 | ␊ |
4770 | //----------------------------------------------------------------------␊ |
4771 | ␊ |
4772 | static void generateXRefPages()␊ |
4773 | {␊ |
4774 | QDictIterator<RefList> di(*Doxygen::xrefLists);␊ |
4775 | RefList *rl;␊ |
4776 | for (di.toFirst();(rl=di.current());++di)␊ |
4777 | {␊ |
4778 | rl->generatePage();␊ |
4779 | }␊ |
4780 | }␊ |
4781 | ␊ |
4782 | //----------------------------------------------------------------------␊ |
4783 | // Copy the documentation in entry `root' to member definition `md' and␊ |
4784 | // set the function declaration of the member to `funcDecl'. If the boolean ␊ |
4785 | // over_load is set the standard overload text is added. ␊ |
4786 | ␊ |
4787 | static void addMemberDocs(EntryNav *rootNav,␊ |
4788 | MemberDef *md, const char *funcDecl,␊ |
4789 | ArgumentList *al,␊ |
4790 | bool over_load,␊ |
4791 | NamespaceSDict *␊ |
4792 | )␊ |
4793 | {␊ |
4794 | Entry *root = rootNav->entry();␊ |
4795 | //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",␊ |
4796 | // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);␊ |
4797 | QCString fDecl=funcDecl;␊ |
4798 | // strip extern specifier␊ |
4799 | fDecl.stripPrefix("extern ");␊ |
4800 | md->setDefinition(fDecl);␊ |
4801 | md->enableCallGraph(root->callGraph);␊ |
4802 | md->enableCallerGraph(root->callerGraph);␊ |
4803 | ClassDef *cd=md->getClassDef();␊ |
4804 | NamespaceDef *nd=md->getNamespaceDef();␊ |
4805 | QCString fullName;␊ |
4806 | if (cd) ␊ |
4807 | fullName = cd->name();␊ |
4808 | else if (nd) ␊ |
4809 | fullName = nd->name();␊ |
4810 | ␊ |
4811 | if (!fullName.isEmpty()) fullName+="::";␊ |
4812 | fullName+=md->name();␊ |
4813 | FileDef *rfd=rootNav->fileDef();␊ |
4814 | ␊ |
4815 | // TODO determine scope based on root not md␊ |
4816 | Definition *rscope = md->getOuterScope();␊ |
4817 | ␊ |
4818 | LockingPtr<ArgumentList> mdAl = md->argumentList();␊ |
4819 | if (al)␊ |
4820 | {␊ |
4821 | //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());␊ |
4822 | mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty());␊ |
4823 | }␊ |
4824 | else␊ |
4825 | {␊ |
4826 | if ( ␊ |
4827 | matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),␊ |
4828 | rscope,rfd,root->argList,␊ |
4829 | TRUE␊ |
4830 | )␊ |
4831 | ) ␊ |
4832 | {␊ |
4833 | //printf("merging arguments (2)\n");␊ |
4834 | mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());␊ |
4835 | }␊ |
4836 | }␊ |
4837 | if (over_load) // the \overload keyword was used␊ |
4838 | {␊ |
4839 | QCString doc=getOverloadDocs();␊ |
4840 | if (!root->doc.isEmpty())␊ |
4841 | {␊ |
4842 | doc+="<p>";␊ |
4843 | doc+=root->doc;␊ |
4844 | }␊ |
4845 | md->setDocumentation(doc,root->docFile,root->docLine); ␊ |
4846 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
4847 | md->setDocsForDefinition(!root->proto);␊ |
4848 | }␊ |
4849 | else ␊ |
4850 | {␊ |
4851 | //printf("overwrite!\n");␊ |
4852 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
4853 | md->setDocsForDefinition(!root->proto);␊ |
4854 | ␊ |
4855 | //printf("overwrite!\n");␊ |
4856 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
4857 | ␊ |
4858 | if (␊ |
4859 | (md->inbodyDocumentation().isEmpty() ||␊ |
4860 | !rootNav->parent()->name().isEmpty()␊ |
4861 | ) && !root->inbodyDocs.isEmpty()␊ |
4862 | )␊ |
4863 | {␊ |
4864 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
4865 | }␊ |
4866 | }␊ |
4867 | ␊ |
4868 | //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",␊ |
4869 | // md->initializer().data(),md->initializer().isEmpty(),␊ |
4870 | // root->initializer.data(),root->initializer.isEmpty()␊ |
4871 | // );␊ |
4872 | if (md->initializer().isEmpty() && !root->initializer.isEmpty())␊ |
4873 | {␊ |
4874 | //printf("setInitializer\n");␊ |
4875 | md->setInitializer(root->initializer);␊ |
4876 | }␊ |
4877 | ␊ |
4878 | md->setMaxInitLines(root->initLines);␊ |
4879 | ␊ |
4880 | if (rfd)␊ |
4881 | {␊ |
4882 | if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1) ␊ |
4883 | )␊ |
4884 | {␊ |
4885 | //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);␊ |
4886 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
4887 | md->setBodyDef(rfd);␊ |
4888 | }␊ |
4889 | ␊ |
4890 | md->setRefItems(root->sli);␊ |
4891 | }␊ |
4892 | ␊ |
4893 | md->enableCallGraph(md->hasCallGraph() || root->callGraph);␊ |
4894 | md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);␊ |
4895 | ␊ |
4896 | md->mergeMemberSpecifiers(root->spec);␊ |
4897 | md->addSectionsToDefinition(root->anchors);␊ |
4898 | addMemberToGroups(root,md);␊ |
4899 | if (cd) cd->insertUsedFile(root->fileName);␊ |
4900 | //printf("root->mGrpId=%d\n",root->mGrpId);␊ |
4901 | if (root->mGrpId!=-1)␊ |
4902 | {␊ |
4903 | if (md->getMemberGroupId()!=-1)␊ |
4904 | {␊ |
4905 | if (md->getMemberGroupId()!=root->mGrpId)␊ |
4906 | {␊ |
4907 | warn(␊ |
4908 | root->fileName,root->startLine,␊ |
4909 | "warning: member %s belongs to two different groups. The second "␊ |
4910 | "one found here will be ignored.",␊ |
4911 | md->name().data()␊ |
4912 | );␊ |
4913 | }␊ |
4914 | }␊ |
4915 | else // set group id␊ |
4916 | {␊ |
4917 | //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());␊ |
4918 | md->setMemberGroupId(root->mGrpId);␊ |
4919 | }␊ |
4920 | }␊ |
4921 | }␊ |
4922 | ␊ |
4923 | //----------------------------------------------------------------------␊ |
4924 | // find a class definition given the scope name and (optionally) a ␊ |
4925 | // template list specifier␊ |
4926 | ␊ |
4927 | static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,␊ |
4928 | const char *scopeName)␊ |
4929 | {␊ |
4930 | ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);␊ |
4931 | return tcd;␊ |
4932 | }␊ |
4933 | ␊ |
4934 | ␊ |
4935 | //----------------------------------------------------------------------␊ |
4936 | // Adds the documentation contained in `root' to a global function␊ |
4937 | // with name `name' and argument list `args' (for overloading) and␊ |
4938 | // function declaration `decl' to the corresponding member definition.␊ |
4939 | ␊ |
4940 | static bool findGlobalMember(EntryNav *rootNav, ␊ |
4941 | const QCString &namespaceName,␊ |
4942 | const char *name, ␊ |
4943 | const char *tempArg,␊ |
4944 | const char *, ␊ |
4945 | const char *decl)␊ |
4946 | {␊ |
4947 | Entry *root = rootNav->entry();␊ |
4948 | Debug::print(Debug::FindMembers,0,␊ |
4949 | "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n",␊ |
4950 | namespaceName.data(),name,tempArg,decl);␊ |
4951 | QCString n=name;␊ |
4952 | if (n.isEmpty()) return FALSE;␊ |
4953 | if (n.find("::")!=-1) return FALSE; // skip undefined class members␊ |
4954 | MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary␊ |
4955 | if (mn==0)␊ |
4956 | {␊ |
4957 | mn=Doxygen::functionNameSDict->find(n); // try without template arguments␊ |
4958 | }␊ |
4959 | if (mn) // function name defined␊ |
4960 | {␊ |
4961 | Debug::print(Debug::FindMembers,0,"3. Found function scope\n");␊ |
4962 | //int count=0;␊ |
4963 | MemberNameIterator mni(*mn);␊ |
4964 | MemberDef *md;␊ |
4965 | bool found=FALSE;␊ |
4966 | for (mni.toFirst();(md=mni.current()) && !found;++mni)␊ |
4967 | {␊ |
4968 | NamespaceDef *nd=md->getNamespaceDef();␊ |
4969 | ␊ |
4970 | //printf("Namespace namespaceName=%s nd=%s\n",␊ |
4971 | // namespaceName.data(),nd ? nd->name().data() : "<none>");␊ |
4972 | ␊ |
4973 | FileDef *fd=rootNav->fileDef();␊ |
4974 | //printf("File %s\n",fd ? fd->name().data() : "<none>");␊ |
4975 | NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;␊ |
4976 | //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;␊ |
4977 | //printf("NamespaceList %p\n",nl);␊ |
4978 | ␊ |
4979 | // search in the list of namespaces that are imported via a ␊ |
4980 | // using declaration␊ |
4981 | bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;␊ |
4982 | ␊ |
4983 | if ((namespaceName.isEmpty() && nd==0) || // not in a namespace␊ |
4984 | (nd && nd->name()==namespaceName) || // or in the same namespace ␊ |
4985 | viaUsingDirective // member in `using' namespace␊ |
4986 | ) ␊ |
4987 | {␊ |
4988 | Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",␊ |
4989 | md->name().data(),namespaceName.data());␊ |
4990 | QCString nsName = nd ? nd->name().data() : "";␊ |
4991 | ␊ |
4992 | NamespaceDef *rnd = 0;␊ |
4993 | if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);␊ |
4994 | ␊ |
4995 | LockingPtr<ArgumentList> mdAl = md->argumentList();␊ |
4996 | bool matching=␊ |
4997 | (mdAl==0 && root->argList->count()==0) ||␊ |
4998 | md->isVariable() || md->isTypedef() || /* in case of function pointers */␊ |
4999 | matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(),␊ |
5000 | rnd ? rnd : Doxygen::globalScope,fd,root->argList,␊ |
5001 | FALSE);␊ |
5002 | ␊ |
5003 | // for template members we need to check if the number of␊ |
5004 | // template arguments is the same, otherwise we are dealing with␊ |
5005 | // different functions.␊ |
5006 | if (matching && root->tArgLists)␊ |
5007 | {␊ |
5008 | LockingPtr<ArgumentList> mdTempl = md->templateArguments();␊ |
5009 | if (mdTempl!=0)␊ |
5010 | {␊ |
5011 | if (root->tArgLists->getLast()->count()!=mdTempl->count())␊ |
5012 | {␊ |
5013 | matching=FALSE;␊ |
5014 | }␊ |
5015 | }␊ |
5016 | }␊ |
5017 | ␊ |
5018 | ␊ |
5019 | //printf("%s<->%s\n",␊ |
5020 | // argListToString(md->argumentList()).data(),␊ |
5021 | // argListToString(root->argList).data());␊ |
5022 | ␊ |
5023 | // for static members we also check if the comment block was found in ␊ |
5024 | // the same file. This is needed because static members with the same␊ |
5025 | // name can be in different files. Thus it would be wrong to just␊ |
5026 | // put the comment block at the first syntactically matching member.␊ |
5027 | if (matching && md->isStatic() && ␊ |
5028 | md->getDefFileName()!=root->fileName && ␊ |
5029 | mn->count()>1)␊ |
5030 | {␊ |
5031 | matching = FALSE;␊ |
5032 | }␊ |
5033 | ␊ |
5034 | if (matching) // add docs to the member␊ |
5035 | {␊ |
5036 | Debug::print(Debug::FindMembers,0,"5. Match found\n");␊ |
5037 | addMemberDocs(rootNav,md,decl,root->argList,FALSE);␊ |
5038 | found=TRUE;␊ |
5039 | }␊ |
5040 | }␊ |
5041 | } ␊ |
5042 | if (!found && root->relatesType != Duplicate) // no match␊ |
5043 | {␊ |
5044 | QCString fullFuncDecl=decl;␊ |
5045 | if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);␊ |
5046 | QCString warnMsg =␊ |
5047 | QCString("warning: no matching file member found for \n")+fullFuncDecl;␊ |
5048 | if (mn->count()>0)␊ |
5049 | {␊ |
5050 | warnMsg+="Possible candidates:\n";␊ |
5051 | for (mni.toFirst();(md=mni.current());++mni)␊ |
5052 | {␊ |
5053 | warnMsg+=" ";␊ |
5054 | warnMsg+=md->declaration();␊ |
5055 | warnMsg+='\n';␊ |
5056 | }␊ |
5057 | }␊ |
5058 | warn(root->fileName,root->startLine,warnMsg);␊ |
5059 | }␊ |
5060 | }␊ |
5061 | else // got docs for an undefined member!␊ |
5062 | {␊ |
5063 | if (root->type!="friend class" && ␊ |
5064 | root->type!="friend struct" &&␊ |
5065 | root->type!="friend union" &&␊ |
5066 | (!Config_getBool("TYPEDEF_HIDES_STRUCT") || ␊ |
5067 | root->type.find("typedef ")==-1)␊ |
5068 | )␊ |
5069 | {␊ |
5070 | warn(root->fileName,root->startLine,␊ |
5071 | "warning: documented function `%s' was not declared or defined.",decl␊ |
5072 | );␊ |
5073 | }␊ |
5074 | }␊ |
5075 | return TRUE;␊ |
5076 | }␊ |
5077 | ␊ |
5078 | static bool isSpecialization(␊ |
5079 | const QList<ArgumentList> &srcTempArgLists,␊ |
5080 | const QList<ArgumentList> &dstTempArgLists␊ |
5081 | )␊ |
5082 | {␊ |
5083 | QListIterator<ArgumentList> srclali(srcTempArgLists);␊ |
5084 | QListIterator<ArgumentList> dstlali(dstTempArgLists);␊ |
5085 | for (;srclali.current();++srclali,++dstlali)␊ |
5086 | {␊ |
5087 | ArgumentList *sal = srclali.current();␊ |
5088 | ArgumentList *dal = dstlali.current();␊ |
5089 | if (!(sal && dal && sal->count()==dal->count())) return TRUE;␊ |
5090 | }␊ |
5091 | return FALSE;␊ |
5092 | }␊ |
5093 | ␊ |
5094 | ␊ |
5095 | static QCString substituteTemplatesInString(␊ |
5096 | const QList<ArgumentList> &srcTempArgLists,␊ |
5097 | const QList<ArgumentList> &dstTempArgLists,␊ |
5098 | ArgumentList *funcTempArgList, // can be used to match template specializations␊ |
5099 | const QCString &src␊ |
5100 | )␊ |
5101 | {␊ |
5102 | QCString dst;␊ |
5103 | QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");␊ |
5104 | //printf("type=%s\n",sa->type.data());␊ |
5105 | int i,p=0,l; ␊ |
5106 | while ((i=re.match(src,p,&l))!=-1) // for each word in srcType␊ |
5107 | {␊ |
5108 | bool found=FALSE;␊ |
5109 | dst+=src.mid(p,i-p);␊ |
5110 | QCString name=src.mid(i,l);␊ |
5111 | ␊ |
5112 | QListIterator<ArgumentList> srclali(srcTempArgLists);␊ |
5113 | QListIterator<ArgumentList> dstlali(dstTempArgLists);␊ |
5114 | for (;srclali.current() && !found;++srclali,++dstlali)␊ |
5115 | {␊ |
5116 | ArgumentListIterator tsali(*srclali.current());␊ |
5117 | ArgumentListIterator tdali(*dstlali.current());␊ |
5118 | Argument *tsa =0,*tda=0, *fa=0;␊ |
5119 | if (funcTempArgList)␊ |
5120 | {␊ |
5121 | fa=funcTempArgList->first();␊ |
5122 | }␊ |
5123 | ␊ |
5124 | for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)␊ |
5125 | {␊ |
5126 | tda = tdali.current();␊ |
5127 | //if (tda) printf("tsa=%s|%s tda=%s|%s\n",␊ |
5128 | // tsa->type.data(),tsa->name.data(),␊ |
5129 | // tda->type.data(),tda->name.data());␊ |
5130 | if (name==tsa->name)␊ |
5131 | {␊ |
5132 | if (tda && tda->name.isEmpty())␊ |
5133 | {␊ |
5134 | int vc=0;␊ |
5135 | if (tda->type.left(6)=="class ") vc=6;␊ |
5136 | else if (tda->type.left(9)=="typename ") vc=9;␊ |
5137 | if (vc>0) // convert type=="class T" to type=="class" name=="T"␊ |
5138 | {␊ |
5139 | tda->name = tda->type.mid(vc);␊ |
5140 | tda->type = tda->type.left(vc-1);␊ |
5141 | }␊ |
5142 | }␊ |
5143 | if (tda && !tda->name.isEmpty())␊ |
5144 | {␊ |
5145 | name=tda->name; // substitute␊ |
5146 | found=TRUE;␊ |
5147 | }␊ |
5148 | else if (fa)␊ |
5149 | {␊ |
5150 | name=fa->type;␊ |
5151 | found=TRUE;␊ |
5152 | }␊ |
5153 | }␊ |
5154 | if (tda) ␊ |
5155 | ++tdali; ␊ |
5156 | else if (fa) ␊ |
5157 | fa=funcTempArgList->next();␊ |
5158 | }␊ |
5159 | //printf(" srcList='%s' dstList='%s faList='%s'\n",␊ |
5160 | // argListToString(srclali.current()).data(),␊ |
5161 | // argListToString(dstlali.current()).data(),␊ |
5162 | // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");␊ |
5163 | }␊ |
5164 | dst+=name; ␊ |
5165 | p=i+l;␊ |
5166 | }␊ |
5167 | dst+=src.right(src.length()-p);␊ |
5168 | //printf(" substituteTemplatesInString(%s)=%s\n",␊ |
5169 | // src.data(),dst.data());␊ |
5170 | return dst;␊ |
5171 | }␊ |
5172 | ␊ |
5173 | static void substituteTemplatesInArgList(␊ |
5174 | const QList<ArgumentList> &srcTempArgLists,␊ |
5175 | const QList<ArgumentList> &dstTempArgLists,␊ |
5176 | ArgumentList *src,␊ |
5177 | ArgumentList *dst,␊ |
5178 | ArgumentList *funcTempArgs = 0␊ |
5179 | )␊ |
5180 | {␊ |
5181 | ArgumentListIterator sali(*src);␊ |
5182 | Argument *sa=0;␊ |
5183 | Argument *da=dst->first();␊ |
5184 | ␊ |
5185 | for (sali.toFirst();(sa=sali.current());++sali) // for each member argument␊ |
5186 | {␊ |
5187 | QCString dstType = substituteTemplatesInString(␊ |
5188 | srcTempArgLists,dstTempArgLists,funcTempArgs,␊ |
5189 | sa->type);␊ |
5190 | QCString dstArray = substituteTemplatesInString(␊ |
5191 | srcTempArgLists,dstTempArgLists,funcTempArgs,␊ |
5192 | sa->array);␊ |
5193 | if (da==0)␊ |
5194 | {␊ |
5195 | da=new Argument(*sa);␊ |
5196 | dst->append(da);␊ |
5197 | da->type=dstType;␊ |
5198 | da->array=dstArray;␊ |
5199 | da=0;␊ |
5200 | }␊ |
5201 | else␊ |
5202 | {␊ |
5203 | da->type=dstType;␊ |
5204 | da->type=dstArray;␊ |
5205 | da=dst->next();␊ |
5206 | }␊ |
5207 | }␊ |
5208 | dst->constSpecifier = src->constSpecifier;␊ |
5209 | dst->volatileSpecifier = src->volatileSpecifier;␊ |
5210 | dst->pureSpecifier = src->pureSpecifier;␊ |
5211 | //printf("substituteTemplatesInArgList: replacing %s with %s\n",␊ |
5212 | // argListToString(src).data(),argListToString(dst).data()␊ |
5213 | // );␊ |
5214 | }␊ |
5215 | ␊ |
5216 | ␊ |
5217 | ␊ |
5218 | /*! This function tries to find a member (in a documented class/file/namespace) ␊ |
5219 | * that corresponds to the function/variable declaration given in \a funcDecl.␊ |
5220 | *␊ |
5221 | * The boolean \a overloaded is used to specify whether or not a standard␊ |
5222 | * overload documentation line should be generated.␊ |
5223 | *␊ |
5224 | * The boolean \a isFunc is a hint that indicates that this is a function␊ |
5225 | * instead of a variable or typedef.␊ |
5226 | */␊ |
5227 | static void findMember(EntryNav *rootNav,␊ |
5228 | QCString funcDecl,␊ |
5229 | bool overloaded,␊ |
5230 | bool isFunc␊ |
5231 | )␊ |
5232 | {␊ |
5233 | Entry *root = rootNav->entry();␊ |
5234 | ␊ |
5235 | Debug::print(Debug::FindMembers,0,␊ |
5236 | "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"␊ |
5237 | "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "␊ |
5238 | "spec=%d lang=%x\n",␊ |
5239 | root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,␊ |
5240 | root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,␊ |
5241 | root->spec,root->lang␊ |
5242 | );␊ |
5243 | ␊ |
5244 | QCString scopeName;␊ |
5245 | QCString className;␊ |
5246 | QCString namespaceName;␊ |
5247 | QCString funcType;␊ |
5248 | QCString funcName;␊ |
5249 | QCString funcArgs;␊ |
5250 | QCString funcTempList;␊ |
5251 | QCString exceptions;␊ |
5252 | QCString funcSpec;␊ |
5253 | bool isRelated=FALSE;␊ |
5254 | bool isMemberOf=FALSE;␊ |
5255 | bool isFriend=FALSE;␊ |
5256 | bool done;␊ |
5257 | do␊ |
5258 | {␊ |
5259 | done=TRUE;␊ |
5260 | if (funcDecl.stripPrefix("friend ")) // treat friends as related members␊ |
5261 | {␊ |
5262 | isFriend=TRUE;␊ |
5263 | done=FALSE;␊ |
5264 | }␊ |
5265 | if (funcDecl.stripPrefix("inline "))␊ |
5266 | {␊ |
5267 | root->spec|=Entry::Inline;␊ |
5268 | done=FALSE;␊ |
5269 | }␊ |
5270 | if (funcDecl.stripPrefix("explicit "))␊ |
5271 | {␊ |
5272 | root->spec|=Entry::Explicit;␊ |
5273 | done=FALSE;␊ |
5274 | }␊ |
5275 | if (funcDecl.stripPrefix("mutable "))␊ |
5276 | {␊ |
5277 | root->spec|=Entry::Mutable;␊ |
5278 | done=FALSE;␊ |
5279 | }␊ |
5280 | if (funcDecl.stripPrefix("virtual "))␊ |
5281 | {␊ |
5282 | done=FALSE;␊ |
5283 | }␊ |
5284 | } while (!done);␊ |
5285 | ␊ |
5286 | // delete any ; from the function declaration␊ |
5287 | int sep;␊ |
5288 | while ((sep=funcDecl.find(';'))!=-1)␊ |
5289 | {␊ |
5290 | funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();␊ |
5291 | }␊ |
5292 | ␊ |
5293 | // make sure the first character is a space to simplify searching.␊ |
5294 | if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");␊ |
5295 | ␊ |
5296 | // remove some superfluous spaces␊ |
5297 | funcDecl= substitute(␊ |
5298 | substitute(␊ |
5299 | substitute(funcDecl,"~ ","~"),␊ |
5300 | ":: ","::"␊ |
5301 | ),␊ |
5302 | " ::","::"␊ |
5303 | ).stripWhiteSpace();␊ |
5304 | ␊ |
5305 | //printf("funcDecl=`%s'\n",funcDecl.data());␊ |
5306 | if (isFriend && funcDecl.left(6)=="class ")␊ |
5307 | {␊ |
5308 | //printf("friend class\n");␊ |
5309 | funcDecl=funcDecl.right(funcDecl.length()-6);␊ |
5310 | funcName = funcDecl.copy();␊ |
5311 | }␊ |
5312 | else if (isFriend && funcDecl.left(7)=="struct ")␊ |
5313 | {␊ |
5314 | funcDecl=funcDecl.right(funcDecl.length()-7);␊ |
5315 | funcName = funcDecl.copy();␊ |
5316 | }␊ |
5317 | else␊ |
5318 | {␊ |
5319 | // extract information from the declarations␊ |
5320 | parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,␊ |
5321 | funcArgs,funcTempList,exceptions␊ |
5322 | );␊ |
5323 | }␊ |
5324 | //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",␊ |
5325 | // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());␊ |
5326 | ␊ |
5327 | // the class name can also be a namespace name, we decide this later.␊ |
5328 | // if a related class name is specified and the class name could␊ |
5329 | // not be derived from the function declaration, then use the␊ |
5330 | // related field.␊ |
5331 | //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",␊ |
5332 | // scopeName.data(),className.data(),namespaceName.data());␊ |
5333 | if (!root->relates.isEmpty()) ␊ |
5334 | { // related member, prefix user specified scope␊ |
5335 | isRelated=TRUE;␊ |
5336 | isMemberOf=(root->relatesType == MemberOf);␊ |
5337 | if (getClass(root->relates)==0 && !scopeName.isEmpty())␊ |
5338 | {␊ |
5339 | scopeName= mergeScopes(scopeName,root->relates);␊ |
5340 | }␊ |
5341 | else ␊ |
5342 | {␊ |
5343 | scopeName = root->relates;␊ |
5344 | }␊ |
5345 | }␊ |
5346 | ␊ |
5347 | if (root->relates.isEmpty() && rootNav->parent() && ␊ |
5348 | ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||␊ |
5349 | (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)␊ |
5350 | ) &&␊ |
5351 | !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName ␊ |
5352 | // with the scope in which it was found␊ |
5353 | {␊ |
5354 | QCString joinedName = rootNav->parent()->name()+"::"+scopeName;␊ |
5355 | if (!scopeName.isEmpty() && ␊ |
5356 | (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))␊ |
5357 | {␊ |
5358 | scopeName = joinedName;␊ |
5359 | }␊ |
5360 | else␊ |
5361 | {␊ |
5362 | scopeName = mergeScopes(rootNav->parent()->name(),scopeName);␊ |
5363 | }␊ |
5364 | }␊ |
5365 | else // see if we can prefix a namespace or class that is used from the file␊ |
5366 | {␊ |
5367 | FileDef *fd=rootNav->fileDef();␊ |
5368 | if (fd)␊ |
5369 | {␊ |
5370 | NamespaceSDict *fnl = fd->getUsedNamespaces();␊ |
5371 | if (fnl)␊ |
5372 | {␊ |
5373 | QCString joinedName;␊ |
5374 | NamespaceDef *fnd;␊ |
5375 | NamespaceSDict::Iterator nsdi(*fnl);␊ |
5376 | for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)␊ |
5377 | {␊ |
5378 | joinedName = fnd->name()+"::"+scopeName;␊ |
5379 | if (Doxygen::namespaceSDict->find(joinedName))␊ |
5380 | {␊ |
5381 | scopeName=joinedName;␊ |
5382 | break;␊ |
5383 | }␊ |
5384 | }␊ |
5385 | }␊ |
5386 | }␊ |
5387 | }␊ |
5388 | scopeName=stripTemplateSpecifiersFromScope(␊ |
5389 | removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec); ␊ |
5390 | ␊ |
5391 | // funcSpec contains the last template specifiers of the given scope.␊ |
5392 | // If this method does not have any template arguments or they are ␊ |
5393 | // empty while funcSpec is not empty we assume this is a ␊ |
5394 | // specialization of a method. If not, we clear the funcSpec and treat␊ |
5395 | // this as a normal method of a template class.␊ |
5396 | if (!(root->tArgLists && ␊ |
5397 | root->tArgLists->count()>0 &&␊ |
5398 | root->tArgLists->first()->count()==0␊ |
5399 | )␊ |
5400 | ) ␊ |
5401 | {␊ |
5402 | funcSpec.resize(0);␊ |
5403 | }␊ |
5404 | ␊ |
5405 | // split scope into a namespace and a class part␊ |
5406 | extractNamespaceName(scopeName,className,namespaceName,TRUE);␊ |
5407 | //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",␊ |
5408 | // scopeName.data(),className.data(),namespaceName.data());␊ |
5409 | ␊ |
5410 | //namespaceName=removeAnonymousScopes(namespaceName);␊ |
5411 | if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...␊ |
5412 | ␊ |
5413 | //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());␊ |
5414 | // merge class and namespace scopes again␊ |
5415 | scopeName.resize(0);␊ |
5416 | if (!namespaceName.isEmpty())␊ |
5417 | {␊ |
5418 | if (className.isEmpty())␊ |
5419 | {␊ |
5420 | scopeName=namespaceName;␊ |
5421 | }␊ |
5422 | else if (!root->relates.isEmpty() || // relates command with explicit scope␊ |
5423 | !getClass(className)) // class name only exists in a namespace␊ |
5424 | {␊ |
5425 | scopeName=namespaceName+"::"+className;␊ |
5426 | }␊ |
5427 | else␊ |
5428 | {␊ |
5429 | scopeName=className;␊ |
5430 | }␊ |
5431 | }␊ |
5432 | else if (!className.isEmpty())␊ |
5433 | {␊ |
5434 | scopeName=className;␊ |
5435 | }␊ |
5436 | //printf("new scope=`%s'\n",scopeName.data());␊ |
5437 | ␊ |
5438 | QCString tempScopeName=scopeName;␊ |
5439 | ClassDef *cd=getClass(scopeName);␊ |
5440 | if (cd)␊ |
5441 | {␊ |
5442 | if (root->tArgLists) root->tArgLists->first();␊ |
5443 | if (funcSpec.isEmpty())␊ |
5444 | {␊ |
5445 | tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists);␊ |
5446 | }␊ |
5447 | else␊ |
5448 | {␊ |
5449 | tempScopeName=scopeName+funcSpec;␊ |
5450 | }␊ |
5451 | }␊ |
5452 | //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",␊ |
5453 | // scopeName.data(),cd,root->tArgLists,tempScopeName.data());␊ |
5454 | ␊ |
5455 | //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());␊ |
5456 | // rebuild the function declaration (needed to get the scope right).␊ |
5457 | if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))␊ |
5458 | {␊ |
5459 | if (!funcType.isEmpty())␊ |
5460 | {␊ |
5461 | if (isFunc) // a function -> we use argList for the arguments␊ |
5462 | {␊ |
5463 | funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;␊ |
5464 | }␊ |
5465 | else␊ |
5466 | {␊ |
5467 | funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;␊ |
5468 | }␊ |
5469 | }␊ |
5470 | else␊ |
5471 | {␊ |
5472 | if (isFunc) // a function => we use argList for the arguments␊ |
5473 | {␊ |
5474 | funcDecl=tempScopeName+"::"+funcName+funcTempList;␊ |
5475 | }␊ |
5476 | else // variable => add `argument' list␊ |
5477 | {␊ |
5478 | funcDecl=tempScopeName+"::"+funcName+funcArgs;␊ |
5479 | }␊ |
5480 | }␊ |
5481 | }␊ |
5482 | else // build declaration without scope␊ |
5483 | {␊ |
5484 | if (!funcType.isEmpty()) // but with a type␊ |
5485 | {␊ |
5486 | if (isFunc) // function => omit argument list␊ |
5487 | {␊ |
5488 | funcDecl=funcType+" "+funcName+funcTempList;␊ |
5489 | }␊ |
5490 | else // variable => add `argument' list␊ |
5491 | {␊ |
5492 | funcDecl=funcType+" "+funcName+funcArgs;␊ |
5493 | }␊ |
5494 | }␊ |
5495 | else // no type␊ |
5496 | {␊ |
5497 | if (isFunc)␊ |
5498 | {␊ |
5499 | funcDecl=funcName+funcTempList;␊ |
5500 | }␊ |
5501 | else␊ |
5502 | {␊ |
5503 | funcDecl=funcName+funcArgs;␊ |
5504 | }␊ |
5505 | }␊ |
5506 | }␊ |
5507 | ␊ |
5508 | if (funcType=="template class" && !funcTempList.isEmpty())␊ |
5509 | return; // ignore explicit template instantiations␊ |
5510 | ␊ |
5511 | Debug::print(Debug::FindMembers,0,␊ |
5512 | "findMember() Parse results:\n"␊ |
5513 | " namespaceName=`%s'\n"␊ |
5514 | " className=`%s`\n"␊ |
5515 | " funcType=`%s'\n"␊ |
5516 | " funcSpec=`%s'\n"␊ |
5517 | " funcName=`%s'\n"␊ |
5518 | " funcArgs=`%s'\n"␊ |
5519 | " funcTempList=`%s'\n"␊ |
5520 | " funcDecl=`%s'\n"␊ |
5521 | " related=`%s'\n" ␊ |
5522 | " exceptions=`%s'\n"␊ |
5523 | " isRelated=%d\n"␊ |
5524 | " isMemberOf=%d\n"␊ |
5525 | " isFriend=%d\n"␊ |
5526 | " isFunc=%d\n\n",␊ |
5527 | namespaceName.data(),className.data(),␊ |
5528 | funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),␊ |
5529 | funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,␊ |
5530 | isFunc␊ |
5531 | );␊ |
5532 | ␊ |
5533 | MemberName *mn=0;␊ |
5534 | if (!funcName.isEmpty()) // function name is valid␊ |
5535 | { ␊ |
5536 | Debug::print(Debug::FindMembers,0,␊ |
5537 | "1. funcName=`%s'\n",funcName.data());␊ |
5538 | if (funcName.left(9)=="operator ") // strip class scope from cast operator␊ |
5539 | {␊ |
5540 | funcName = substitute(funcName,className+"::","");␊ |
5541 | }␊ |
5542 | if (!funcTempList.isEmpty()) // try with member specialization␊ |
5543 | {␊ |
5544 | mn=Doxygen::memberNameSDict->find(funcName+funcTempList);␊ |
5545 | }␊ |
5546 | if (mn==0) // try without specialization␊ |
5547 | {␊ |
5548 | mn=Doxygen::memberNameSDict->find(funcName);␊ |
5549 | }␊ |
5550 | if (!isRelated && mn) // function name already found␊ |
5551 | {␊ |
5552 | Debug::print(Debug::FindMembers,0,␊ |
5553 | "2. member name exists (%d members with this name)\n",mn->count());␊ |
5554 | if (!className.isEmpty()) // class name is valid␊ |
5555 | {␊ |
5556 | if (funcSpec.isEmpty()) // not a member specialization␊ |
5557 | {␊ |
5558 | int count=0;␊ |
5559 | int noMatchCount=0;␊ |
5560 | MemberNameIterator mni(*mn);␊ |
5561 | MemberDef *md;␊ |
5562 | bool memFound=FALSE;␊ |
5563 | for (mni.toFirst();!memFound && (md=mni.current());++mni)␊ |
5564 | {␊ |
5565 | ClassDef *cd=md->getClassDef();␊ |
5566 | Debug::print(Debug::FindMembers,0,␊ |
5567 | "3. member definition found, "␊ |
5568 | "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",␊ |
5569 | scopeName.data(),cd ? cd->name().data() : "<none>",␊ |
5570 | md->argsString(),␊ |
5571 | root->fileName.data());␊ |
5572 | //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());␊ |
5573 | FileDef *fd=rootNav->fileDef();␊ |
5574 | NamespaceDef *nd=0;␊ |
5575 | if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);␊ |
5576 | ␊ |
5577 | //printf("scopeName %s->%s\n",scopeName.data(),␊ |
5578 | // stripTemplateSpecifiersFromScope(scopeName,FALSE).data());␊ |
5579 | ␊ |
5580 | ClassDef *tcd=findClassDefinition(fd,nd,scopeName);␊ |
5581 | if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)␊ |
5582 | {␊ |
5583 | // don't be fooled by anonymous scopes␊ |
5584 | tcd=cd;␊ |
5585 | }␊ |
5586 | //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",␊ |
5587 | // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);␊ |
5588 | ␊ |
5589 | if (cd && tcd==cd) // member's classes match␊ |
5590 | {␊ |
5591 | Debug::print(Debug::FindMembers,0,␊ |
5592 | "4. class definition %s found\n",cd->name().data());␊ |
5593 | ␊ |
5594 | // get the template parameter lists found at the member declaration␊ |
5595 | QList<ArgumentList> declTemplArgs;␊ |
5596 | cd->getTemplateParameterLists(declTemplArgs);␊ |
5597 | LockingPtr<ArgumentList> templAl = md->templateArguments();␊ |
5598 | if (templAl!=0)␊ |
5599 | {␊ |
5600 | declTemplArgs.append(templAl.pointer());␊ |
5601 | }␊ |
5602 | ␊ |
5603 | // get the template parameter lists found at the member definition␊ |
5604 | QList<ArgumentList> *defTemplArgs = root->tArgLists;␊ |
5605 | //printf("defTemplArgs=%p\n",defTemplArgs);␊ |
5606 | ␊ |
5607 | // do we replace the decl argument lists with the def argument lists?␊ |
5608 | bool substDone=FALSE;␊ |
5609 | ArgumentList *argList=0;␊ |
5610 | ␊ |
5611 | /* substitute the occurrences of class template names in the ␊ |
5612 | * argument list before matching ␊ |
5613 | */␊ |
5614 | LockingPtr<ArgumentList> mdAl = md->argumentList();␊ |
5615 | if (declTemplArgs.count()>0 && defTemplArgs &&␊ |
5616 | declTemplArgs.count()==defTemplArgs->count() &&␊ |
5617 | mdAl.pointer()␊ |
5618 | )␊ |
5619 | {␊ |
5620 | /* the function definition has template arguments␊ |
5621 | * and the class definition also has template arguments, so␊ |
5622 | * we must substitute the template names of the class by that␊ |
5623 | * of the function definition before matching.␊ |
5624 | */␊ |
5625 | argList = new ArgumentList;␊ |
5626 | substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,␊ |
5627 | mdAl.pointer(),argList);␊ |
5628 | ␊ |
5629 | substDone=TRUE;␊ |
5630 | }␊ |
5631 | else /* no template arguments, compare argument lists directly */␊ |
5632 | {␊ |
5633 | argList = mdAl.pointer();␊ |
5634 | }␊ |
5635 | ␊ |
5636 | Debug::print(Debug::FindMembers,0,␊ |
5637 | "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",␊ |
5638 | argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),␊ |
5639 | className.data(),namespaceName.data()␊ |
5640 | );␊ |
5641 | ␊ |
5642 | bool matching=␊ |
5643 | md->isVariable() || md->isTypedef() || // needed for function pointers␊ |
5644 | (mdAl.pointer()==0 && root->argList->count()==0) || ␊ |
5645 | matchArguments2(␊ |
5646 | md->getClassDef(),md->getFileDef(),argList, ␊ |
5647 | cd,fd,root->argList,␊ |
5648 | TRUE);␊ |
5649 | ␊ |
5650 | Debug::print(Debug::FindMembers,0,␊ |
5651 | "6. match results of matchArguments2 = %d\n",matching);␊ |
5652 | ␊ |
5653 | if (substDone) // found a new argument list␊ |
5654 | {␊ |
5655 | if (matching) // replace member's argument list␊ |
5656 | {␊ |
5657 | md->setDefinitionTemplateParameterLists(root->tArgLists);␊ |
5658 | md->setArgumentList(argList); // new owner of the list => no delete␊ |
5659 | }␊ |
5660 | else // no match ␊ |
5661 | {␊ |
5662 | if (!funcTempList.isEmpty() && ␊ |
5663 | isSpecialization(declTemplArgs,*defTemplArgs))␊ |
5664 | {␊ |
5665 | // check if we are dealing with a partial template␊ |
5666 | // specialization. In this case we add it to the class␊ |
5667 | // even though the member arguments do not match.␊ |
5668 | ␊ |
5669 | // TODO: copy other aspects?␊ |
5670 | root->protection=md->protection(); // copy protection level␊ |
5671 | addMethodToClass(rootNav,cd,md->name(),isFriend);␊ |
5672 | return;␊ |
5673 | }␊ |
5674 | delete argList;␊ |
5675 | }␊ |
5676 | }␊ |
5677 | if (matching) ␊ |
5678 | {␊ |
5679 | addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);␊ |
5680 | count++;␊ |
5681 | memFound=TRUE;␊ |
5682 | }␊ |
5683 | } ␊ |
5684 | else if (cd && cd!=tcd) // we did find a class with the same name as cd␊ |
5685 | // but in a different namespace␊ |
5686 | {␊ |
5687 | noMatchCount++;␊ |
5688 | }␊ |
5689 | } ␊ |
5690 | if (count==0 && rootNav->parent() && ␊ |
5691 | rootNav->parent()->section()==Entry::OBJCIMPL_SEC)␊ |
5692 | {␊ |
5693 | goto localObjCMethod;␊ |
5694 | }␊ |
5695 | if (count==0 && !(isFriend && funcType=="class"))␊ |
5696 | {␊ |
5697 | int candidates=0;␊ |
5698 | ClassDef *ccd = 0, *ecd = 0;␊ |
5699 | MemberDef *cmd = 0, *emd = 0;␊ |
5700 | if (mn->count()>0)␊ |
5701 | {␊ |
5702 | //printf("Assume template class\n");␊ |
5703 | for (mni.toFirst();(md=mni.current());++mni)␊ |
5704 | {␊ |
5705 | ccd=md->getClassDef();␊ |
5706 | cmd=md;␊ |
5707 | //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());␊ |
5708 | if (ccd!=0 && rightScopeMatch(ccd->name(),className)) ␊ |
5709 | {␊ |
5710 | LockingPtr<ArgumentList> templAl = md->templateArguments();␊ |
5711 | if (root->tArgLists && templAl!=0 &&␊ |
5712 | root->tArgLists->getLast()->count()<=templAl->count())␊ |
5713 | { ␊ |
5714 | addMethodToClass(rootNav,ccd,md->name(),isFriend);␊ |
5715 | return;␊ |
5716 | }␊ |
5717 | if (md->argsString()==argListToString(root->argList,TRUE,FALSE))␊ |
5718 | { // exact argument list match -> remember␊ |
5719 | ecd = ccd;␊ |
5720 | emd = cmd;␊ |
5721 | }␊ |
5722 | candidates++;␊ |
5723 | }␊ |
5724 | }␊ |
5725 | }␊ |
5726 | static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING");␊ |
5727 | if (!strictProtoMatching)␊ |
5728 | {␊ |
5729 | if (candidates==1 && ccd && cmd)␊ |
5730 | {␊ |
5731 | // we didn't find an actual match on argument lists, but there is only 1 member with this␊ |
5732 | // name in the same scope, so that has to be the one. ␊ |
5733 | addMemberDocs(rootNav,cmd,funcDecl,0,overloaded,0);␊ |
5734 | return;␊ |
5735 | }␊ |
5736 | else if (candidates>1 && ecd && emd)␊ |
5737 | {␊ |
5738 | // we didn't find a unique match using type resolution, ␊ |
5739 | // but one of the matches has the exact same signature so␊ |
5740 | // we take that one.␊ |
5741 | addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);␊ |
5742 | return;␊ |
5743 | }␊ |
5744 | }␊ |
5745 | ␊ |
5746 | QCString warnMsg = "warning: no ";␊ |
5747 | if (noMatchCount>1) warnMsg+="uniquely ";␊ |
5748 | warnMsg+="matching class member found for \n";␊ |
5749 | ␊ |
5750 | if (root->tArgLists)␊ |
5751 | {␊ |
5752 | QListIterator<ArgumentList> alli(*root->tArgLists);␊ |
5753 | ArgumentList *al;␊ |
5754 | for (;(al=alli.current());++alli)␊ |
5755 | {␊ |
5756 | warnMsg+=" template ";␊ |
5757 | warnMsg+=tempArgListToString(al);␊ |
5758 | warnMsg+='\n';␊ |
5759 | }␊ |
5760 | }␊ |
5761 | QCString fullFuncDecl=funcDecl.copy();␊ |
5762 | if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);␊ |
5763 | ␊ |
5764 | warnMsg+=" ";␊ |
5765 | warnMsg+=fullFuncDecl;␊ |
5766 | warnMsg+='\n';␊ |
5767 | ␊ |
5768 | if (candidates>0)␊ |
5769 | {␊ |
5770 | warnMsg+="Possible candidates:\n";␊ |
5771 | for (mni.toFirst();(md=mni.current());++mni)␊ |
5772 | {␊ |
5773 | ClassDef *cd=md->getClassDef();␊ |
5774 | if (cd!=0 && rightScopeMatch(cd->name(),className))␊ |
5775 | {␊ |
5776 | LockingPtr<ArgumentList> templAl = md->templateArguments();␊ |
5777 | if (templAl!=0)␊ |
5778 | {␊ |
5779 | warnMsg+=" template ";␊ |
5780 | warnMsg+=tempArgListToString(templAl.pointer());␊ |
5781 | warnMsg+='\n';␊ |
5782 | }␊ |
5783 | warnMsg+=" ";␊ |
5784 | if (md->typeString()) ␊ |
5785 | {␊ |
5786 | warnMsg+=md->typeString();␊ |
5787 | warnMsg+=' ';␊ |
5788 | }␊ |
5789 | QCString qScope = cd->qualifiedNameWithTemplateParameters();␊ |
5790 | if (!qScope.isEmpty()) ␊ |
5791 | warnMsg+=qScope+"::"+md->name();␊ |
5792 | if (md->argsString()) ␊ |
5793 | warnMsg+=md->argsString();␊ |
5794 | if (noMatchCount>1) ␊ |
5795 | {␊ |
5796 | QCString lineFile;␊ |
5797 | lineFile.sprintf(" at line %d of file ",md->getDefLine());␊ |
5798 | warnMsg+=lineFile+md->getDefFileName();␊ |
5799 | }␊ |
5800 | ␊ |
5801 | warnMsg+='\n';␊ |
5802 | }␊ |
5803 | }␊ |
5804 | }␊ |
5805 | warn_simple(root->fileName,root->startLine,warnMsg);␊ |
5806 | }␊ |
5807 | }␊ |
5808 | else if (cd) // member specialization␊ |
5809 | {␊ |
5810 | MemberNameIterator mni(*mn);␊ |
5811 | MemberDef *declMd=0;␊ |
5812 | MemberDef *md=0;␊ |
5813 | for (mni.toFirst();(md=mni.current());++mni)␊ |
5814 | {␊ |
5815 | if (md->getClassDef()==cd) ␊ |
5816 | {␊ |
5817 | // TODO: we should probably also check for matching arguments␊ |
5818 | declMd = md;␊ |
5819 | break;␊ |
5820 | }␊ |
5821 | }␊ |
5822 | MemberDef::MemberType mtype=MemberDef::Function;␊ |
5823 | ArgumentList *tArgList = new ArgumentList;␊ |
5824 | // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);␊ |
5825 | md=new MemberDef(␊ |
5826 | root->fileName,root->startLine,␊ |
5827 | funcType,funcName,funcArgs,exceptions,␊ |
5828 | declMd ? declMd->protection() : root->protection,␊ |
5829 | root->virt,root->stat,Member,␊ |
5830 | mtype,tArgList,root->argList);␊ |
5831 | //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());␊ |
5832 | md->setTagInfo(rootNav->tagInfo());␊ |
5833 | md->setMemberClass(cd);␊ |
5834 | md->setTemplateSpecialization(TRUE);␊ |
5835 | md->setTypeConstraints(root->typeConstr);␊ |
5836 | md->setDefinition(funcDecl);␊ |
5837 | md->enableCallGraph(root->callGraph);␊ |
5838 | md->enableCallerGraph(root->callerGraph);␊ |
5839 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
5840 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
5841 | md->setDocsForDefinition(!root->proto);␊ |
5842 | md->setPrototype(root->proto);␊ |
5843 | md->addSectionsToDefinition(root->anchors);␊ |
5844 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
5845 | FileDef *fd=rootNav->fileDef();␊ |
5846 | md->setBodyDef(fd);␊ |
5847 | md->setMemberSpecifiers(root->spec);␊ |
5848 | md->setMemberGroupId(root->mGrpId);␊ |
5849 | mn->append(md);␊ |
5850 | cd->insertMember(md);␊ |
5851 | md->setRefItems(root->sli);␊ |
5852 | delete tArgList;␊ |
5853 | }␊ |
5854 | else␊ |
5855 | {␊ |
5856 | //printf("*** Specialized member %s of unknown scope %s%s found!\n",␊ |
5857 | // scopeName.data(),funcName.data(),funcArgs.data());␊ |
5858 | }␊ |
5859 | }␊ |
5860 | else if (overloaded) // check if the function belongs to only one class ␊ |
5861 | {␊ |
5862 | // for unique overloaded member we allow the class to be␊ |
5863 | // omitted, this is to be Qt compatable. Using this should ␊ |
5864 | // however be avoided, because it is error prone␊ |
5865 | MemberNameIterator mni(*mn);␊ |
5866 | MemberDef *md=mni.toFirst();␊ |
5867 | ASSERT(md);␊ |
5868 | ClassDef *cd=md->getClassDef();␊ |
5869 | ASSERT(cd);␊ |
5870 | QCString className=cd->name().copy();␊ |
5871 | ++mni;␊ |
5872 | bool unique=TRUE;␊ |
5873 | for (;(md=mni.current());++mni)␊ |
5874 | {␊ |
5875 | ClassDef *cd=md->getClassDef();␊ |
5876 | if (className!=cd->name()) unique=FALSE; ␊ |
5877 | } ␊ |
5878 | if (unique)␊ |
5879 | {␊ |
5880 | MemberDef::MemberType mtype;␊ |
5881 | if (root->mtype==Signal) mtype=MemberDef::Signal;␊ |
5882 | else if (root->mtype==Slot) mtype=MemberDef::Slot;␊ |
5883 | else if (root->mtype==DCOP) mtype=MemberDef::DCOP;␊ |
5884 | else mtype=MemberDef::Function;␊ |
5885 | ␊ |
5886 | // new overloaded member function␊ |
5887 | ArgumentList *tArgList = ␊ |
5888 | getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);␊ |
5889 | //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());␊ |
5890 | MemberDef *md=new MemberDef(␊ |
5891 | root->fileName,root->startLine,␊ |
5892 | funcType,funcName,funcArgs,exceptions,␊ |
5893 | root->protection,root->virt,root->stat,Related,␊ |
5894 | mtype,tArgList,root->argList);␊ |
5895 | md->setTagInfo(rootNav->tagInfo());␊ |
5896 | md->setTypeConstraints(root->typeConstr);␊ |
5897 | md->setMemberClass(cd);␊ |
5898 | md->setDefinition(funcDecl);␊ |
5899 | md->enableCallGraph(root->callGraph);␊ |
5900 | md->enableCallerGraph(root->callerGraph);␊ |
5901 | QCString doc=getOverloadDocs();␊ |
5902 | doc+="<p>";␊ |
5903 | doc+=root->doc;␊ |
5904 | md->setDocumentation(doc,root->docFile,root->docLine);␊ |
5905 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
5906 | md->setDocsForDefinition(!root->proto);␊ |
5907 | md->setPrototype(root->proto);␊ |
5908 | md->addSectionsToDefinition(root->anchors);␊ |
5909 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
5910 | FileDef *fd=rootNav->fileDef();␊ |
5911 | md->setBodyDef(fd);␊ |
5912 | md->setMemberSpecifiers(root->spec);␊ |
5913 | md->setMemberGroupId(root->mGrpId);␊ |
5914 | mn->append(md);␊ |
5915 | cd->insertMember(md);␊ |
5916 | cd->insertUsedFile(root->fileName);␊ |
5917 | md->setRefItems(root->sli);␊ |
5918 | }␊ |
5919 | }␊ |
5920 | else // unrelated function with the same name as a member␊ |
5921 | {␊ |
5922 | if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))␊ |
5923 | {␊ |
5924 | QCString fullFuncDecl=funcDecl.copy();␊ |
5925 | if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);␊ |
5926 | warn(root->fileName,root->startLine,␊ |
5927 | "warning: Cannot determine class for function\n%s",␊ |
5928 | fullFuncDecl.data()␊ |
5929 | ); ␊ |
5930 | }␊ |
5931 | }␊ |
5932 | }␊ |
5933 | else if (isRelated && !root->relates.isEmpty())␊ |
5934 | {␊ |
5935 | Debug::print(Debug::FindMembers,0,"2. related function\n"␊ |
5936 | " scopeName=%s className=%s\n",scopeName.data(),className.data());␊ |
5937 | if (className.isEmpty()) className=root->relates;␊ |
5938 | ClassDef *cd;␊ |
5939 | //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());␊ |
5940 | if ((cd=getClass(scopeName)))␊ |
5941 | {␊ |
5942 | bool newMember=TRUE; // assume we have a new member␊ |
5943 | bool newMemberName=FALSE; ␊ |
5944 | bool isDefine=FALSE;␊ |
5945 | {␊ |
5946 | MemberName *mn = Doxygen::functionNameSDict->find(funcName);␊ |
5947 | if (mn)␊ |
5948 | {␊ |
5949 | MemberDef *md = mn->first();␊ |
5950 | while (md && !isDefine)␊ |
5951 | {␊ |
5952 | isDefine = isDefine || md->isDefine();␊ |
5953 | md = mn->next();␊ |
5954 | }␊ |
5955 | }␊ |
5956 | }␊ |
5957 | ␊ |
5958 | FileDef *fd=rootNav->fileDef();␊ |
5959 | ␊ |
5960 | if ((mn=Doxygen::memberNameSDict->find(funcName))==0)␊ |
5961 | {␊ |
5962 | mn=new MemberName(funcName);␊ |
5963 | newMemberName=TRUE; // we create a new member name␊ |
5964 | }␊ |
5965 | else␊ |
5966 | {␊ |
5967 | MemberDef *rmd=mn->first();␊ |
5968 | while (rmd && newMember) // see if we got another member with matching arguments␊ |
5969 | {␊ |
5970 | LockingPtr<ArgumentList> rmdAl = rmd->argumentList();␊ |
5971 | ␊ |
5972 | newMember=␊ |
5973 | !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),␊ |
5974 | cd,fd,root->argList,␊ |
5975 | TRUE);␊ |
5976 | if (newMember) rmd=mn->next();␊ |
5977 | }␊ |
5978 | if (!newMember && rmd) // member already exists as rmd -> add docs␊ |
5979 | {␊ |
5980 | //printf("addMemberDocs for related member %s\n",root->name.data());␊ |
5981 | //rmd->setMemberDefTemplateArguments(root->mtArgList);␊ |
5982 | addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);␊ |
5983 | }␊ |
5984 | }␊ |
5985 | ␊ |
5986 | if (newMember) // need to create a new member␊ |
5987 | {␊ |
5988 | MemberDef::MemberType mtype;␊ |
5989 | if (isDefine)␊ |
5990 | mtype=MemberDef::Define;␊ |
5991 | else if (root->mtype==Signal) ␊ |
5992 | mtype=MemberDef::Signal;␊ |
5993 | else if (root->mtype==Slot) ␊ |
5994 | mtype=MemberDef::Slot;␊ |
5995 | else if (root->mtype==DCOP)␊ |
5996 | mtype=MemberDef::DCOP;␊ |
5997 | else␊ |
5998 | mtype=MemberDef::Function;␊ |
5999 | ␊ |
6000 | //printf("New related name `%s' `%d'\n",funcName.data(),␊ |
6001 | // root->argList ? (int)root->argList->count() : -1);␊ |
6002 | ␊ |
6003 | // new related (member) function␊ |
6004 | #if 0 // removed as it doesn't handle related template functions correctly␊ |
6005 | ArgumentList *tArgList = ␊ |
6006 | getTemplateArgumentsFromName(scopeName+"::"+funcName,root->tArgLists);␊ |
6007 | MemberDef *md=new MemberDef(␊ |
6008 | root->fileName,root->startLine,␊ |
6009 | funcType,funcName,funcArgs,exceptions,␊ |
6010 | root->protection,root->virt,root->stat,TRUE,␊ |
6011 | mtype,tArgList,funcArgs.isEmpty() ? 0 : root->argList);␊ |
6012 | #endif␊ |
6013 | // first note that we pass:␊ |
6014 | // (root->tArgLists ? root->tArgLists->last() : 0)␊ |
6015 | // for the template arguments fo the new "member."␊ |
6016 | // this accurately reflects the template arguments of␊ |
6017 | // the related function, which don't have to do with␊ |
6018 | // those of the related class.␊ |
6019 | MemberDef *md=new MemberDef(␊ |
6020 | root->fileName,root->startLine,␊ |
6021 | funcType,funcName,funcArgs,exceptions,␊ |
6022 | root->protection,root->virt,␊ |
6023 | root->stat && !isMemberOf,␊ |
6024 | isMemberOf ? Foreign : isRelated ? Related : Member,␊ |
6025 | mtype,␊ |
6026 | (root->tArgLists ? root->tArgLists->last() : 0),␊ |
6027 | funcArgs.isEmpty() ? 0 : root->argList);␊ |
6028 | // ␊ |
6029 | // we still have the problem that␊ |
6030 | // MemberDef::writeDocumentation() in memberdef.cpp␊ |
6031 | // writes the template argument list for the class,␊ |
6032 | // as if this member is a member of the class.␊ |
6033 | // fortunately, MemberDef::writeDocumentation() has␊ |
6034 | // a special mechanism that allows us to totally␊ |
6035 | // override the set of template argument lists that␊ |
6036 | // are printed. We use that and set it to the␊ |
6037 | // template argument lists of the related function.␊ |
6038 | //␊ |
6039 | md->setDefinitionTemplateParameterLists(root->tArgLists);␊ |
6040 | ␊ |
6041 | md->setTagInfo(rootNav->tagInfo());␊ |
6042 | ␊ |
6043 | ␊ |
6044 | ␊ |
6045 | //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",␊ |
6046 | // funcName.data(),funcDecl.data(),root->bodyLine);␊ |
6047 | ␊ |
6048 | // try to find the matching line number of the body from the␊ |
6049 | // global function list ␊ |
6050 | bool found=FALSE;␊ |
6051 | if (root->bodyLine==-1)␊ |
6052 | {␊ |
6053 | MemberName *rmn=Doxygen::functionNameSDict->find(funcName);␊ |
6054 | if (rmn)␊ |
6055 | {␊ |
6056 | MemberDef *rmd=rmn->first();␊ |
6057 | while (rmd && !found) // see if we got another member with matching arguments␊ |
6058 | {␊ |
6059 | LockingPtr<ArgumentList> rmdAl = rmd->argumentList();␊ |
6060 | // check for matching argument lists␊ |
6061 | if (␊ |
6062 | matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),␊ |
6063 | cd,fd,root->argList,␊ |
6064 | TRUE)␊ |
6065 | )␊ |
6066 | {␊ |
6067 | found=TRUE;␊ |
6068 | }␊ |
6069 | if (!found) rmd=rmn->next();␊ |
6070 | }␊ |
6071 | if (rmd) // member found -> copy line number info␊ |
6072 | {␊ |
6073 | md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());␊ |
6074 | md->setBodyDef(rmd->getBodyDef());␊ |
6075 | //md->setBodyMember(rmd);␊ |
6076 | }␊ |
6077 | }␊ |
6078 | }␊ |
6079 | if (!found) // line number could not be found or is available in this␊ |
6080 | // entry␊ |
6081 | {␊ |
6082 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
6083 | md->setBodyDef(fd);␊ |
6084 | }␊ |
6085 | ␊ |
6086 | //if (root->mGrpId!=-1) ␊ |
6087 | //{␊ |
6088 | // md->setMemberGroup(memberGroupDict[root->mGrpId]);␊ |
6089 | //}␊ |
6090 | md->setMemberClass(cd);␊ |
6091 | md->setMemberSpecifiers(root->spec);␊ |
6092 | md->setDefinition(funcDecl);␊ |
6093 | md->enableCallGraph(root->callGraph);␊ |
6094 | md->enableCallerGraph(root->callerGraph);␊ |
6095 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
6096 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
6097 | md->setDocsForDefinition(!root->proto);␊ |
6098 | md->setPrototype(root->proto);␊ |
6099 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
6100 | md->addSectionsToDefinition(root->anchors);␊ |
6101 | md->setMemberGroupId(root->mGrpId);␊ |
6102 | //md->setMemberDefTemplateArguments(root->mtArgList);␊ |
6103 | mn->append(md);␊ |
6104 | cd->insertMember(md);␊ |
6105 | cd->insertUsedFile(root->fileName);␊ |
6106 | md->setRefItems(root->sli);␊ |
6107 | if (root->relatesType == Duplicate) md->setRelatedAlso(cd);␊ |
6108 | addMemberToGroups(root,md);␊ |
6109 | //printf("Adding member=%s\n",md->name().data());␊ |
6110 | if (newMemberName)␊ |
6111 | {␊ |
6112 | //Doxygen::memberNameList.append(mn);␊ |
6113 | //Doxygen::memberNameDict.insert(funcName,mn);␊ |
6114 | Doxygen::memberNameSDict->append(funcName,mn);␊ |
6115 | }␊ |
6116 | }␊ |
6117 | if (root->relatesType == Duplicate)␊ |
6118 | {␊ |
6119 | if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))␊ |
6120 | {␊ |
6121 | QCString fullFuncDecl=funcDecl.copy();␊ |
6122 | if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);␊ |
6123 | warn(root->fileName,root->startLine,␊ |
6124 | "warning: Cannot determine file/namespace for relatedalso function\n%s",␊ |
6125 | fullFuncDecl.data()␊ |
6126 | ); ␊ |
6127 | }␊ |
6128 | }␊ |
6129 | }␊ |
6130 | else␊ |
6131 | {␊ |
6132 | warn_undoc(root->fileName,root->startLine,␊ |
6133 | "warning: class `%s' for related function `%s' is not "␊ |
6134 | "documented.", ␊ |
6135 | className.data(),funcName.data()␊ |
6136 | );␊ |
6137 | }␊ |
6138 | }␊ |
6139 | else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)␊ |
6140 | {␊ |
6141 | localObjCMethod:␊ |
6142 | ClassDef *cd;␊ |
6143 | //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());␊ |
6144 | if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))␊ |
6145 | {␊ |
6146 | //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());␊ |
6147 | MemberDef *md=new MemberDef(␊ |
6148 | root->fileName,root->startLine,␊ |
6149 | funcType,funcName,funcArgs,exceptions,␊ |
6150 | root->protection,root->virt,root->stat,Member,␊ |
6151 | MemberDef::Function,0,root->argList);␊ |
6152 | md->setTagInfo(rootNav->tagInfo());␊ |
6153 | md->makeImplementationDetail();␊ |
6154 | md->setMemberClass(cd);␊ |
6155 | md->setDefinition(funcDecl);␊ |
6156 | md->enableCallGraph(root->callGraph);␊ |
6157 | md->enableCallerGraph(root->callerGraph);␊ |
6158 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
6159 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
6160 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
6161 | md->setDocsForDefinition(!root->proto);␊ |
6162 | md->setPrototype(root->proto);␊ |
6163 | md->addSectionsToDefinition(root->anchors);␊ |
6164 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
6165 | FileDef *fd=rootNav->fileDef();␊ |
6166 | md->setBodyDef(fd);␊ |
6167 | md->setMemberSpecifiers(root->spec);␊ |
6168 | md->setMemberGroupId(root->mGrpId);␊ |
6169 | cd->insertMember(md);␊ |
6170 | cd->insertUsedFile(root->fileName);␊ |
6171 | md->setRefItems(root->sli);␊ |
6172 | if ((mn=Doxygen::memberNameSDict->find(root->name)))␊ |
6173 | {␊ |
6174 | mn->append(md);␊ |
6175 | }␊ |
6176 | else ␊ |
6177 | {␊ |
6178 | mn = new MemberName(root->name);␊ |
6179 | mn->append(md);␊ |
6180 | Doxygen::memberNameSDict->append(root->name,mn);␊ |
6181 | }␊ |
6182 | }␊ |
6183 | else␊ |
6184 | {␊ |
6185 | // local objective C method found for class without interface␊ |
6186 | }␊ |
6187 | }␊ |
6188 | else // unrelated not overloaded member found␊ |
6189 | {␊ |
6190 | bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl);␊ |
6191 | if (className.isEmpty() && !globMem)␊ |
6192 | {␊ |
6193 | warn(root->fileName,root->startLine,␊ |
6194 | "warning: class for member `%s' cannot "␊ |
6195 | "be found.", funcName.data()␊ |
6196 | ); ␊ |
6197 | }␊ |
6198 | else if (!className.isEmpty() && !globMem)␊ |
6199 | {␊ |
6200 | warn(root->fileName,root->startLine,␊ |
6201 | "warning: member `%s' of class `%s' cannot be found",␊ |
6202 | funcName.data(),className.data());␊ |
6203 | }␊ |
6204 | }␊ |
6205 | }␊ |
6206 | else␊ |
6207 | {␊ |
6208 | // this should not be called␊ |
6209 | warn(root->fileName,root->startLine,␊ |
6210 | "warning: member with no name found.");␊ |
6211 | }␊ |
6212 | return;␊ |
6213 | } ␊ |
6214 | ␊ |
6215 | //----------------------------------------------------------------------␊ |
6216 | // find the members corresponding to the different documentation blocks␊ |
6217 | // that are extracted from the sources.␊ |
6218 | ␊ |
6219 | static void filterMemberDocumentation(EntryNav *rootNav)␊ |
6220 | {␊ |
6221 | Entry *root = rootNav->entry();␊ |
6222 | int i=-1,l;␊ |
6223 | Debug::print(Debug::FindMembers,0,␊ |
6224 | "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n",␊ |
6225 | root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId␊ |
6226 | );␊ |
6227 | //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());␊ |
6228 | bool isFunc=TRUE;␊ |
6229 | ␊ |
6230 | if (root->relatesType == Duplicate && !root->relates.isEmpty())␊ |
6231 | {␊ |
6232 | QCString tmp = root->relates;␊ |
6233 | root->relates.resize(0);␊ |
6234 | filterMemberDocumentation(rootNav);␊ |
6235 | root->relates = tmp;␊ |
6236 | }␊ |
6237 | ␊ |
6238 | if ( // detect func variable/typedef to func ptr␊ |
6239 | (i=findFunctionPtr(root->type,root->lang,&l))!=-1 ␊ |
6240 | )␊ |
6241 | {␊ |
6242 | //printf("Fixing function pointer!\n");␊ |
6243 | // fix type and argument␊ |
6244 | root->args.prepend(root->type.right(root->type.length()-i-l));␊ |
6245 | root->type=root->type.left(i+l);␊ |
6246 | //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());␊ |
6247 | isFunc=FALSE;␊ |
6248 | }␊ |
6249 | else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1)) ␊ |
6250 | // detect function types marked as functions␊ |
6251 | {␊ |
6252 | isFunc=FALSE;␊ |
6253 | }␊ |
6254 | ␊ |
6255 | //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);␊ |
6256 | if (root->section==Entry::MEMBERDOC_SEC)␊ |
6257 | {␊ |
6258 | //printf("Documentation for inline member `%s' found args=`%s'\n",␊ |
6259 | // root->name.data(),root->args.data());␊ |
6260 | //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());␊ |
6261 | if (root->type.isEmpty())␊ |
6262 | {␊ |
6263 | findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);␊ |
6264 | }␊ |
6265 | else␊ |
6266 | {␊ |
6267 | findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);␊ |
6268 | }␊ |
6269 | }␊ |
6270 | else if (root->section==Entry::OVERLOADDOC_SEC) ␊ |
6271 | {␊ |
6272 | //printf("Overloaded member %s found\n",root->name.data());␊ |
6273 | findMember(rootNav,root->name,TRUE,isFunc);␊ |
6274 | }␊ |
6275 | else if ␊ |
6276 | ((root->section==Entry::FUNCTION_SEC // function␊ |
6277 | || ␊ |
6278 | (root->section==Entry::VARIABLE_SEC && // variable␊ |
6279 | !root->type.isEmpty() && // with a type␊ |
6280 | g_compoundKeywordDict.find(root->type)==0 // that is not a keyword ␊ |
6281 | // (to skip forward declaration of class etc.)␊ |
6282 | )␊ |
6283 | ) ␊ |
6284 | )␊ |
6285 | {␊ |
6286 | //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",␊ |
6287 | // root->name.data(),root->args.data(),root->exception.data());␊ |
6288 | //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());␊ |
6289 | //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());␊ |
6290 | if (root->type=="friend class" || root->type=="friend struct" || ␊ |
6291 | root->type=="friend union")␊ |
6292 | {␊ |
6293 | findMember(rootNav,␊ |
6294 | root->type+" "+␊ |
6295 | root->name,␊ |
6296 | FALSE,FALSE);␊ |
6297 | ␊ |
6298 | }␊ |
6299 | else if (!root->type.isEmpty())␊ |
6300 | {␊ |
6301 | findMember(rootNav,␊ |
6302 | root->type+" "+␊ |
6303 | root->inside+␊ |
6304 | root->name+␊ |
6305 | root->args+␊ |
6306 | root->exception,␊ |
6307 | FALSE,isFunc);␊ |
6308 | }␊ |
6309 | else␊ |
6310 | {␊ |
6311 | findMember(rootNav,␊ |
6312 | root->inside+␊ |
6313 | root->name+␊ |
6314 | root->args+␊ |
6315 | root->exception,␊ |
6316 | FALSE,isFunc);␊ |
6317 | }␊ |
6318 | }␊ |
6319 | else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())␊ |
6320 | {␊ |
6321 | findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());␊ |
6322 | }␊ |
6323 | else if (root->section==Entry::VARIABLEDOC_SEC)␊ |
6324 | {␊ |
6325 | //printf("Documentation for variable %s found\n",root->name.data());␊ |
6326 | //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data());␊ |
6327 | findMember(rootNav,root->name,FALSE,FALSE);␊ |
6328 | }␊ |
6329 | else␊ |
6330 | {␊ |
6331 | // skip section ␊ |
6332 | //printf("skip section\n");␊ |
6333 | }␊ |
6334 | }␊ |
6335 | ␊ |
6336 | static void findMemberDocumentation(EntryNav *rootNav)␊ |
6337 | {␊ |
6338 | if (rootNav->section()==Entry::MEMBERDOC_SEC ||␊ |
6339 | rootNav->section()==Entry::OVERLOADDOC_SEC ||␊ |
6340 | rootNav->section()==Entry::FUNCTION_SEC ||␊ |
6341 | rootNav->section()==Entry::VARIABLE_SEC ||␊ |
6342 | rootNav->section()==Entry::VARIABLEDOC_SEC ||␊ |
6343 | rootNav->section()==Entry::DEFINE_SEC␊ |
6344 | )␊ |
6345 | {␊ |
6346 | rootNav->loadEntry(g_storage);␊ |
6347 | ␊ |
6348 | filterMemberDocumentation(rootNav);␊ |
6349 | ␊ |
6350 | rootNav->releaseEntry();␊ |
6351 | }␊ |
6352 | if (rootNav->children())␊ |
6353 | {␊ |
6354 | EntryNavListIterator eli(*rootNav->children());␊ |
6355 | EntryNav *e;␊ |
6356 | for (;(e=eli.current());++eli)␊ |
6357 | {␊ |
6358 | if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);␊ |
6359 | }␊ |
6360 | }␊ |
6361 | }␊ |
6362 | ␊ |
6363 | //----------------------------------------------------------------------␊ |
6364 | ␊ |
6365 | static void findObjCMethodDefinitions(EntryNav *rootNav)␊ |
6366 | {␊ |
6367 | if (rootNav->children())␊ |
6368 | {␊ |
6369 | EntryNavListIterator eli(*rootNav->children());␊ |
6370 | EntryNav *objCImplNav;␊ |
6371 | for (;(objCImplNav=eli.current());++eli)␊ |
6372 | {␊ |
6373 | if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())␊ |
6374 | {␊ |
6375 | EntryNavListIterator seli(*objCImplNav->children());␊ |
6376 | EntryNav *objCMethodNav;␊ |
6377 | for (;(objCMethodNav=seli.current());++seli)␊ |
6378 | {␊ |
6379 | if (objCMethodNav->section()==Entry::FUNCTION_SEC)␊ |
6380 | {␊ |
6381 | objCMethodNav->loadEntry(g_storage);␊ |
6382 | Entry *objCMethod = objCMethodNav->entry();␊ |
6383 | ␊ |
6384 | //Printf(" Found ObjC method definition %s\n",objCMethod->name.data());␊ |
6385 | findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+␊ |
6386 | objCMethod->name+" "+objCMethod->args, FALSE,TRUE);␊ |
6387 | objCMethod->section=Entry::EMPTY_SEC;␊ |
6388 | ␊ |
6389 | objCMethodNav->releaseEntry();␊ |
6390 | }␊ |
6391 | }␊ |
6392 | }␊ |
6393 | }␊ |
6394 | }␊ |
6395 | }␊ |
6396 | ␊ |
6397 | //----------------------------------------------------------------------␊ |
6398 | // find and add the enumeration to their classes, namespaces or files␊ |
6399 | ␊ |
6400 | static void findEnums(EntryNav *rootNav)␊ |
6401 | {␊ |
6402 | if (rootNav->section()==Entry::ENUM_SEC)␊ |
6403 | // non anonymous enumeration␊ |
6404 | {␊ |
6405 | rootNav->loadEntry(g_storage);␊ |
6406 | Entry *root = rootNav->entry();␊ |
6407 | ␊ |
6408 | MemberDef *md=0;␊ |
6409 | ClassDef *cd=0;␊ |
6410 | FileDef *fd=0;␊ |
6411 | NamespaceDef *nd=0;␊ |
6412 | MemberNameSDict *mnsd=0;␊ |
6413 | bool isGlobal;␊ |
6414 | bool isRelated=FALSE;␊ |
6415 | bool isMemberOf=FALSE;␊ |
6416 | //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());␊ |
6417 | int i;␊ |
6418 | ␊ |
6419 | QCString name;␊ |
6420 | QCString scope;␊ |
6421 | ␊ |
6422 | if ((i=root->name.findRev("::"))!=-1) // scope is specified␊ |
6423 | {␊ |
6424 | scope=root->name.left(i); // extract scope␊ |
6425 | name=root->name.right(root->name.length()-i-2); // extract name␊ |
6426 | if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);␊ |
6427 | }␊ |
6428 | else // no scope, check the scope in which the docs where found␊ |
6429 | {␊ |
6430 | if (( rootNav->parent()->section() & Entry::SCOPE_MASK )␊ |
6431 | && !rootNav->parent()->name().isEmpty()␊ |
6432 | ) // found enum docs inside a compound␊ |
6433 | {␊ |
6434 | scope=rootNav->parent()->name();␊ |
6435 | if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);␊ |
6436 | }␊ |
6437 | name=root->name;␊ |
6438 | }␊ |
6439 | ␊ |
6440 | if (!root->relates.isEmpty()) ␊ |
6441 | { // related member, prefix user specified scope␊ |
6442 | isRelated=TRUE;␊ |
6443 | isMemberOf=(root->relatesType == MemberOf);␊ |
6444 | if (getClass(root->relates)==0 && !scope.isEmpty())␊ |
6445 | scope=mergeScopes(scope,root->relates);␊ |
6446 | else ␊ |
6447 | scope=root->relates.copy();␊ |
6448 | if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);␊ |
6449 | }␊ |
6450 | ␊ |
6451 | if (cd && !name.isEmpty()) // found a enum inside a compound␊ |
6452 | {␊ |
6453 | //printf("Enum `%s'::`%s'\n",cd->name(),name.data());␊ |
6454 | fd=0;␊ |
6455 | mnsd=Doxygen::memberNameSDict;␊ |
6456 | isGlobal=FALSE;␊ |
6457 | }␊ |
6458 | else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace␊ |
6459 | {␊ |
6460 | mnsd=Doxygen::functionNameSDict;␊ |
6461 | isGlobal=TRUE;␊ |
6462 | }␊ |
6463 | else // found a global enum␊ |
6464 | {␊ |
6465 | fd=rootNav->fileDef();␊ |
6466 | mnsd=Doxygen::functionNameSDict;␊ |
6467 | isGlobal=TRUE;␊ |
6468 | }␊ |
6469 | ␊ |
6470 | if (!name.isEmpty())␊ |
6471 | {␊ |
6472 | // new enum type␊ |
6473 | md = new MemberDef(␊ |
6474 | root->fileName,root->startLine,␊ |
6475 | 0,name,0,0,␊ |
6476 | root->protection,Normal,FALSE,␊ |
6477 | isMemberOf ? Foreign : isRelated ? Related : Member,␊ |
6478 | MemberDef::Enumeration,␊ |
6479 | 0,0);␊ |
6480 | md->setTagInfo(rootNav->tagInfo());␊ |
6481 | if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);␊ |
6482 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
6483 | md->setBodyDef(rootNav->fileDef());␊ |
6484 | //printf("Enum %s definition at line %d of %s: protection=%d\n",␊ |
6485 | // root->name.data(),root->bodyLine,root->fileName.data(),root->protection);␊ |
6486 | md->addSectionsToDefinition(root->anchors);␊ |
6487 | md->setMemberGroupId(root->mGrpId);␊ |
6488 | md->enableCallGraph(root->callGraph);␊ |
6489 | md->enableCallerGraph(root->callerGraph);␊ |
6490 | //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);␊ |
6491 | md->setRefItems(root->sli);␊ |
6492 | //printf("found enum %s nd=%p\n",name.data(),nd);␊ |
6493 | bool defSet=FALSE;␊ |
6494 | if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')␊ |
6495 | {␊ |
6496 | if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))␊ |
6497 | {␊ |
6498 | md->setDefinition(name); ␊ |
6499 | }␊ |
6500 | else␊ |
6501 | {␊ |
6502 | md->setDefinition(nd->name()+"::"+name); ␊ |
6503 | }␊ |
6504 | //printf("definition=%s\n",md->definition());␊ |
6505 | defSet=TRUE;␊ |
6506 | md->setNamespace(nd);␊ |
6507 | nd->insertMember(md);␊ |
6508 | }␊ |
6509 | ␊ |
6510 | // even if we have already added the enum to a namespace, we still␊ |
6511 | // also want to add it to other appropriate places such as file␊ |
6512 | // or class.␊ |
6513 | if (isGlobal)␊ |
6514 | {␊ |
6515 | if (!defSet) md->setDefinition(name);␊ |
6516 | if (fd==0 && rootNav->parent())␊ |
6517 | {␊ |
6518 | fd=rootNav->parent()->fileDef();␊ |
6519 | }␊ |
6520 | if (fd) ␊ |
6521 | {␊ |
6522 | md->setFileDef(fd);␊ |
6523 | fd->insertMember(md);␊ |
6524 | }␊ |
6525 | }␊ |
6526 | else if (cd)␊ |
6527 | {␊ |
6528 | if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))␊ |
6529 | {␊ |
6530 | md->setDefinition(name); ␊ |
6531 | }␊ |
6532 | else␊ |
6533 | {␊ |
6534 | md->setDefinition(cd->name()+"::"+name); ␊ |
6535 | }␊ |
6536 | cd->insertMember(md);␊ |
6537 | cd->insertUsedFile(root->fileName);␊ |
6538 | }␊ |
6539 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
6540 | md->setDocsForDefinition(!root->proto);␊ |
6541 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
6542 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
6543 | ␊ |
6544 | //printf("Adding member=%s\n",md->name().data());␊ |
6545 | MemberName *mn;␊ |
6546 | if ((mn=(*mnsd)[name]))␊ |
6547 | {␊ |
6548 | // this is used if the same enum is in multiple namespaces/classes␊ |
6549 | mn->append(md);␊ |
6550 | }␊ |
6551 | else // new enum name␊ |
6552 | {␊ |
6553 | mn = new MemberName(name);␊ |
6554 | mn->append(md);␊ |
6555 | mnsd->append(name,mn);␊ |
6556 | //printf("add %s to new memberName. Now %d members\n",␊ |
6557 | // name.data(),mn->count());␊ |
6558 | }␊ |
6559 | addMemberToGroups(root,md);␊ |
6560 | ␊ |
6561 | #if 0␊ |
6562 | if (rootNav->children())␊ |
6563 | {␊ |
6564 | EntryNavListIterator eli(*rootNav->children());␊ |
6565 | EntryNav *e;␊ |
6566 | for (;(e=eli.current());++eli)␊ |
6567 | {␊ |
6568 | //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated);␊ |
6569 | MemberName *fmn=0;␊ |
6570 | MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;␊ |
6571 | if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) ␊ |
6572 | // get list of members with the same name as the field␊ |
6573 | {␊ |
6574 | MemberNameIterator fmni(*fmn);␊ |
6575 | MemberDef *fmd;␊ |
6576 | for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) ␊ |
6577 | {␊ |
6578 | if (fmd->isEnumValue())␊ |
6579 | {␊ |
6580 | //printf("found enum value with same name\n");␊ |
6581 | if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')␊ |
6582 | {␊ |
6583 | NamespaceDef *fnd=fmd->getNamespaceDef();␊ |
6584 | if (fnd==nd) // enum value is inside a namespace␊ |
6585 | {␊ |
6586 | md->insertEnumField(fmd);␊ |
6587 | fmd->setEnumScope(md);␊ |
6588 | }␊ |
6589 | }␊ |
6590 | else if (isGlobal)␊ |
6591 | {␊ |
6592 | FileDef *ffd=fmd->getFileDef();␊ |
6593 | if (ffd==fd) // enum value has file scope␊ |
6594 | {␊ |
6595 | md->insertEnumField(fmd);␊ |
6596 | fmd->setEnumScope(md);␊ |
6597 | }␊ |
6598 | }␊ |
6599 | else if (isRelated && cd) // reparent enum value to␊ |
6600 | // match the enum's scope␊ |
6601 | {␊ |
6602 | md->insertEnumField(fmd); // add field def to list␊ |
6603 | fmd->setEnumScope(md); // cross ref with enum name␊ |
6604 | fmd->setEnumClassScope(cd); // cross ref with enum name␊ |
6605 | fmd->setOuterScope(cd);␊ |
6606 | fmd->makeRelated();␊ |
6607 | cd->insertMember(fmd);␊ |
6608 | }␊ |
6609 | else␊ |
6610 | {␊ |
6611 | ClassDef *fcd=fmd->getClassDef();␊ |
6612 | if (fcd==cd) // enum value is inside a class␊ |
6613 | {␊ |
6614 | //printf("Inserting enum field %s in enum scope %s\n",␊ |
6615 | // fmd->name().data(),md->name().data());␊ |
6616 | md->insertEnumField(fmd); // add field def to list␊ |
6617 | fmd->setEnumScope(md); // cross ref with enum name␊ |
6618 | }␊ |
6619 | }␊ |
6620 | } ␊ |
6621 | }␊ |
6622 | }␊ |
6623 | }␊ |
6624 | }␊ |
6625 | #endif␊ |
6626 | }␊ |
6627 | ␊ |
6628 | rootNav->releaseEntry();␊ |
6629 | }␊ |
6630 | else␊ |
6631 | {␊ |
6632 | RECURSE_ENTRYTREE(findEnums,rootNav);␊ |
6633 | }␊ |
6634 | }␊ |
6635 | ␊ |
6636 | //----------------------------------------------------------------------␊ |
6637 | ␊ |
6638 | static void addEnumValuesToEnums(EntryNav *rootNav)␊ |
6639 | {␊ |
6640 | if (rootNav->section()==Entry::ENUM_SEC)␊ |
6641 | // non anonymous enumeration␊ |
6642 | {␊ |
6643 | rootNav->loadEntry(g_storage);␊ |
6644 | Entry *root = rootNav->entry();␊ |
6645 | ␊ |
6646 | ClassDef *cd=0;␊ |
6647 | FileDef *fd=0;␊ |
6648 | NamespaceDef *nd=0;␊ |
6649 | MemberNameSDict *mnsd=0;␊ |
6650 | bool isGlobal;␊ |
6651 | bool isRelated=FALSE;␊ |
6652 | //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());␊ |
6653 | int i;␊ |
6654 | ␊ |
6655 | QCString name;␊ |
6656 | QCString scope;␊ |
6657 | ␊ |
6658 | if ((i=root->name.findRev("::"))!=-1) // scope is specified␊ |
6659 | {␊ |
6660 | scope=root->name.left(i); // extract scope␊ |
6661 | name=root->name.right(root->name.length()-i-2); // extract name␊ |
6662 | if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);␊ |
6663 | }␊ |
6664 | else // no scope, check the scope in which the docs where found␊ |
6665 | {␊ |
6666 | if (( rootNav->parent()->section() & Entry::SCOPE_MASK )␊ |
6667 | && !rootNav->parent()->name().isEmpty()␊ |
6668 | ) // found enum docs inside a compound␊ |
6669 | {␊ |
6670 | scope=rootNav->parent()->name();␊ |
6671 | if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);␊ |
6672 | }␊ |
6673 | name=root->name;␊ |
6674 | }␊ |
6675 | ␊ |
6676 | if (!root->relates.isEmpty()) ␊ |
6677 | { // related member, prefix user specified scope␊ |
6678 | isRelated=TRUE;␊ |
6679 | if (getClass(root->relates)==0 && !scope.isEmpty())␊ |
6680 | scope=mergeScopes(scope,root->relates);␊ |
6681 | else ␊ |
6682 | scope=root->relates.copy();␊ |
6683 | if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);␊ |
6684 | }␊ |
6685 | ␊ |
6686 | if (cd && !name.isEmpty()) // found a enum inside a compound␊ |
6687 | {␊ |
6688 | //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());␊ |
6689 | fd=0;␊ |
6690 | mnsd=Doxygen::memberNameSDict;␊ |
6691 | isGlobal=FALSE;␊ |
6692 | }␊ |
6693 | else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace␊ |
6694 | {␊ |
6695 | //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());␊ |
6696 | mnsd=Doxygen::functionNameSDict;␊ |
6697 | isGlobal=TRUE;␊ |
6698 | }␊ |
6699 | else // found a global enum␊ |
6700 | {␊ |
6701 | fd=rootNav->fileDef();␊ |
6702 | //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());␊ |
6703 | mnsd=Doxygen::functionNameSDict;␊ |
6704 | isGlobal=TRUE;␊ |
6705 | }␊ |
6706 | ␊ |
6707 | if (!name.isEmpty())␊ |
6708 | {␊ |
6709 | MemberName *mn = mnsd->find(name); // for all members with this name␊ |
6710 | if (mn)␊ |
6711 | {␊ |
6712 | MemberNameIterator mni(*mn);␊ |
6713 | MemberDef *md;␊ |
6714 | for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list␊ |
6715 | {␊ |
6716 | if (md->isEnumerate() && rootNav->children())␊ |
6717 | {␊ |
6718 | EntryNavListIterator eli(*rootNav->children()); // for each enum value␊ |
6719 | EntryNav *e;␊ |
6720 | for (;(e=eli.current());++eli)␊ |
6721 | {␊ |
6722 | SrcLangExt sle;␊ |
6723 | if (rootNav->fileDef() &&␊ |
6724 | ( (sle=getLanguageFromFileName(rootNav->fileDef()->name()))==SrcLangExt_CSharp␊ |
6725 | || sle==SrcLangExt_Java || sle==SrcLangExt_XML␊ |
6726 | )␊ |
6727 | )␊ |
6728 | {␊ |
6729 | // Unlike C++, for C# enum value are only inside the enum ␊ |
6730 | // scope, so we must create them here and only add them to the␊ |
6731 | // enum␊ |
6732 | e->loadEntry(g_storage);␊ |
6733 | Entry *root = e->entry();␊ |
6734 | if (md->qualifiedName()==rootNav->name()) // enum value scope matches that of the enum␊ |
6735 | {␊ |
6736 | MemberDef *fmd=new MemberDef(␊ |
6737 | root->fileName,root->startLine,␊ |
6738 | root->type,root->name,root->args,0,␊ |
6739 | Public, Normal,root->stat,Member,␊ |
6740 | MemberDef::EnumValue,0,0);␊ |
6741 | if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());␊ |
6742 | else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());␊ |
6743 | else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());␊ |
6744 | fmd->setOuterScope(md->getOuterScope());␊ |
6745 | fmd->setTagInfo(e->tagInfo());␊ |
6746 | fmd->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
6747 | fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
6748 | fmd->addSectionsToDefinition(root->anchors);␊ |
6749 | fmd->setInitializer(root->initializer);␊ |
6750 | fmd->setMaxInitLines(root->initLines);␊ |
6751 | fmd->setMemberGroupId(root->mGrpId);␊ |
6752 | fmd->setExplicitExternal(root->explicitExternal);␊ |
6753 | fmd->setRefItems(root->sli);␊ |
6754 | if (fmd)␊ |
6755 | {␊ |
6756 | md->insertEnumField(fmd);␊ |
6757 | fmd->setEnumScope(md);␊ |
6758 | }␊ |
6759 | }␊ |
6760 | e->releaseEntry();␊ |
6761 | }␊ |
6762 | else␊ |
6763 | {␊ |
6764 | //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);␊ |
6765 | MemberName *fmn=0;␊ |
6766 | MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;␊ |
6767 | if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()])) ␊ |
6768 | // get list of members with the same name as the field␊ |
6769 | {␊ |
6770 | MemberNameIterator fmni(*fmn);␊ |
6771 | MemberDef *fmd;␊ |
6772 | for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni) ␊ |
6773 | {␊ |
6774 | if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope␊ |
6775 | {␊ |
6776 | //printf("found enum value with same name %s in scope %s\n",␊ |
6777 | // fmd->name().data(),fmd->getOuterScope()->name().data());␊ |
6778 | if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')␊ |
6779 | {␊ |
6780 | NamespaceDef *fnd=fmd->getNamespaceDef();␊ |
6781 | if (fnd==nd) // enum value is inside a namespace␊ |
6782 | {␊ |
6783 | md->insertEnumField(fmd);␊ |
6784 | fmd->setEnumScope(md);␊ |
6785 | }␊ |
6786 | }␊ |
6787 | else if (isGlobal)␊ |
6788 | {␊ |
6789 | FileDef *ffd=fmd->getFileDef();␊ |
6790 | if (ffd==fd) // enum value has file scope␊ |
6791 | {␊ |
6792 | md->insertEnumField(fmd);␊ |
6793 | fmd->setEnumScope(md);␊ |
6794 | }␊ |
6795 | }␊ |
6796 | else if (isRelated && cd) // reparent enum value to␊ |
6797 | // match the enum's scope␊ |
6798 | {␊ |
6799 | md->insertEnumField(fmd); // add field def to list␊ |
6800 | fmd->setEnumScope(md); // cross ref with enum name␊ |
6801 | fmd->setEnumClassScope(cd); // cross ref with enum name␊ |
6802 | fmd->setOuterScope(cd);␊ |
6803 | fmd->makeRelated();␊ |
6804 | cd->insertMember(fmd);␊ |
6805 | }␊ |
6806 | else␊ |
6807 | {␊ |
6808 | ClassDef *fcd=fmd->getClassDef();␊ |
6809 | if (fcd==cd) // enum value is inside a class␊ |
6810 | {␊ |
6811 | //printf("Inserting enum field %s in enum scope %s\n",␊ |
6812 | // fmd->name().data(),md->name().data());␊ |
6813 | md->insertEnumField(fmd); // add field def to list␊ |
6814 | fmd->setEnumScope(md); // cross ref with enum name␊ |
6815 | }␊ |
6816 | }␊ |
6817 | } ␊ |
6818 | }␊ |
6819 | }␊ |
6820 | }␊ |
6821 | }␊ |
6822 | }␊ |
6823 | }␊ |
6824 | }␊ |
6825 | }␊ |
6826 | ␊ |
6827 | rootNav->releaseEntry();␊ |
6828 | }␊ |
6829 | else␊ |
6830 | {␊ |
6831 | RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);␊ |
6832 | }␊ |
6833 | }␊ |
6834 | ␊ |
6835 | ␊ |
6836 | //----------------------------------------------------------------------␊ |
6837 | // find the documentation blocks for the enumerations␊ |
6838 | ␊ |
6839 | static void findEnumDocumentation(EntryNav *rootNav)␊ |
6840 | {␊ |
6841 | if (rootNav->section()==Entry::ENUMDOC_SEC␊ |
6842 | && !rootNav->name().isEmpty()␊ |
6843 | && rootNav->name().at(0)!='@' // skip anonymous enums␊ |
6844 | )␊ |
6845 | {␊ |
6846 | rootNav->loadEntry(g_storage);␊ |
6847 | Entry *root = rootNav->entry();␊ |
6848 | ␊ |
6849 | //printf("Found docs for enum with name `%s' in context %s\n",␊ |
6850 | // root->name.data(),root->parent->name.data());␊ |
6851 | int i;␊ |
6852 | QCString name;␊ |
6853 | QCString scope;␊ |
6854 | if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name␊ |
6855 | {␊ |
6856 | name=root->name.right(root->name.length()-i-2); // extract name␊ |
6857 | scope=root->name.left(i); // extract scope␊ |
6858 | //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());␊ |
6859 | }␊ |
6860 | else // just the name␊ |
6861 | {␊ |
6862 | name=root->name;␊ |
6863 | }␊ |
6864 | if (( rootNav->parent()->section() & Entry::SCOPE_MASK )␊ |
6865 | && !rootNav->parent()->name().isEmpty()␊ |
6866 | ) // found enum docs inside a compound␊ |
6867 | {␊ |
6868 | if (!scope.isEmpty()) scope.prepend("::");␊ |
6869 | scope.prepend(rootNav->parent()->name());␊ |
6870 | }␊ |
6871 | ClassDef *cd=getClass(scope);␊ |
6872 | ␊ |
6873 | if (!name.isEmpty())␊ |
6874 | {␊ |
6875 | bool found=FALSE;␊ |
6876 | if (cd)␊ |
6877 | {␊ |
6878 | //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());␊ |
6879 | QCString className=cd->name().copy();␊ |
6880 | MemberName *mn=Doxygen::memberNameSDict->find(name);␊ |
6881 | if (mn)␊ |
6882 | {␊ |
6883 | MemberNameIterator mni(*mn);␊ |
6884 | MemberDef *md;␊ |
6885 | for (mni.toFirst();(md=mni.current()) && !found;++mni)␊ |
6886 | {␊ |
6887 | ClassDef *cd=md->getClassDef();␊ |
6888 | if (cd && cd->name()==className && md->isEnumerate())␊ |
6889 | {␊ |
6890 | // documentation outside a compound overrides the documentation inside it␊ |
6891 | #if 0␊ |
6892 | if (!md->documentation() || rootNav->parent()->name().isEmpty()) ␊ |
6893 | #endif␊ |
6894 | {␊ |
6895 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
6896 | md->setDocsForDefinition(!root->proto);␊ |
6897 | }␊ |
6898 | ␊ |
6899 | // brief descriptions inside a compound override the documentation ␊ |
6900 | // outside it␊ |
6901 | #if 0␊ |
6902 | if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())␊ |
6903 | #endif␊ |
6904 | {␊ |
6905 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
6906 | }␊ |
6907 | ␊ |
6908 | if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())␊ |
6909 | {␊ |
6910 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
6911 | }␊ |
6912 | ␊ |
6913 | if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)␊ |
6914 | {␊ |
6915 | md->setMemberGroupId(root->mGrpId);␊ |
6916 | }␊ |
6917 | ␊ |
6918 | md->addSectionsToDefinition(root->anchors);␊ |
6919 | md->setRefItems(root->sli);␊ |
6920 | ␊ |
6921 | GroupDef *gd=md->getGroupDef();␊ |
6922 | if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is␊ |
6923 | {␊ |
6924 | addMemberToGroups(root,md);␊ |
6925 | }␊ |
6926 | ␊ |
6927 | found=TRUE;␊ |
6928 | }␊ |
6929 | }␊ |
6930 | }␊ |
6931 | else␊ |
6932 | {␊ |
6933 | //printf("MemberName %s not found!\n",name.data());␊ |
6934 | }␊ |
6935 | }␊ |
6936 | else // enum outside class ␊ |
6937 | {␊ |
6938 | //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);␊ |
6939 | MemberName *mn=Doxygen::functionNameSDict->find(name);␊ |
6940 | if (mn)␊ |
6941 | {␊ |
6942 | MemberNameIterator mni(*mn);␊ |
6943 | MemberDef *md;␊ |
6944 | for (mni.toFirst();(md=mni.current()) && !found;++mni)␊ |
6945 | {␊ |
6946 | if (md->isEnumerate())␊ |
6947 | {␊ |
6948 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
6949 | md->setDocsForDefinition(!root->proto);␊ |
6950 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
6951 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
6952 | md->addSectionsToDefinition(root->anchors);␊ |
6953 | md->setMemberGroupId(root->mGrpId);␊ |
6954 | ␊ |
6955 | GroupDef *gd=md->getGroupDef();␊ |
6956 | if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is␊ |
6957 | {␊ |
6958 | addMemberToGroups(root,md);␊ |
6959 | }␊ |
6960 | ␊ |
6961 | found=TRUE;␊ |
6962 | }␊ |
6963 | }␊ |
6964 | }␊ |
6965 | } ␊ |
6966 | if (!found)␊ |
6967 | {␊ |
6968 | warn(root->fileName,root->startLine,␊ |
6969 | "warning: Documentation for undefined enum `%s' found.",␊ |
6970 | name.data()␊ |
6971 | );␊ |
6972 | }␊ |
6973 | }␊ |
6974 | ␊ |
6975 | rootNav->releaseEntry();␊ |
6976 | }␊ |
6977 | RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);␊ |
6978 | }␊ |
6979 | ␊ |
6980 | // seach for each enum (member or function) in mnl if it has documented ␊ |
6981 | // enum values.␊ |
6982 | static void findDEV(const MemberNameSDict &mnsd)␊ |
6983 | {␊ |
6984 | MemberName *mn;␊ |
6985 | MemberNameSDict::Iterator mnli(mnsd);␊ |
6986 | // for each member name␊ |
6987 | for (mnli.toFirst();(mn=mnli.current());++mnli)␊ |
6988 | {␊ |
6989 | MemberDef *md;␊ |
6990 | MemberNameIterator mni(*mn);␊ |
6991 | // for each member definition␊ |
6992 | for (mni.toFirst();(md=mni.current());++mni)␊ |
6993 | {␊ |
6994 | if (md->isEnumerate()) // member is an enum␊ |
6995 | {␊ |
6996 | LockingPtr<MemberList> fmdl = md->enumFieldList();␊ |
6997 | int documentedEnumValues=0;␊ |
6998 | if (fmdl!=0) // enum has values␊ |
6999 | {␊ |
7000 | MemberListIterator fmni(*fmdl);␊ |
7001 | MemberDef *fmd;␊ |
7002 | // for each enum value␊ |
7003 | for (fmni.toFirst();(fmd=fmni.current());++fmni)␊ |
7004 | {␊ |
7005 | if (fmd->isLinkableInProject()) documentedEnumValues++;␊ |
7006 | }␊ |
7007 | }␊ |
7008 | // at least one enum value is documented␊ |
7009 | if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);␊ |
7010 | }␊ |
7011 | }␊ |
7012 | }␊ |
7013 | }␊ |
7014 | ␊ |
7015 | // seach for each enum (member or function) if it has documented enum ␊ |
7016 | // values.␊ |
7017 | static void findDocumentedEnumValues()␊ |
7018 | {␊ |
7019 | findDEV(*Doxygen::memberNameSDict);␊ |
7020 | findDEV(*Doxygen::functionNameSDict); ␊ |
7021 | }␊ |
7022 | ␊ |
7023 | //----------------------------------------------------------------------␊ |
7024 | ␊ |
7025 | static void addMembersToIndex()␊ |
7026 | {␊ |
7027 | MemberName *mn;␊ |
7028 | MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);␊ |
7029 | // for each member name␊ |
7030 | for (mnli.toFirst();(mn=mnli.current());++mnli)␊ |
7031 | {␊ |
7032 | MemberDef *md;␊ |
7033 | MemberNameIterator mni(*mn);␊ |
7034 | // for each member definition␊ |
7035 | for (mni.toFirst();(md=mni.current());++mni)␊ |
7036 | {␊ |
7037 | addClassMemberNameToIndex(md);␊ |
7038 | }␊ |
7039 | }␊ |
7040 | MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);␊ |
7041 | // for each member name␊ |
7042 | for (fnli.toFirst();(mn=fnli.current());++fnli)␊ |
7043 | {␊ |
7044 | MemberDef *md;␊ |
7045 | MemberNameIterator mni(*mn);␊ |
7046 | // for each member definition␊ |
7047 | for (mni.toFirst();(md=mni.current());++mni)␊ |
7048 | {␊ |
7049 | if (md->getNamespaceDef())␊ |
7050 | {␊ |
7051 | addNamespaceMemberNameToIndex(md);␊ |
7052 | }␊ |
7053 | else␊ |
7054 | {␊ |
7055 | addFileMemberNameToIndex(md);␊ |
7056 | }␊ |
7057 | }␊ |
7058 | }␊ |
7059 | }␊ |
7060 | ␊ |
7061 | //----------------------------------------------------------------------␊ |
7062 | // computes the relation between all members. For each member `m'␊ |
7063 | // the members that override the implementation of `m' are searched and␊ |
7064 | // the member that `m' overrides is searched.␊ |
7065 | ␊ |
7066 | static void computeMemberRelations()␊ |
7067 | {␊ |
7068 | MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);␊ |
7069 | MemberName *mn;␊ |
7070 | for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name␊ |
7071 | {␊ |
7072 | MemberNameIterator mdi(*mn);␊ |
7073 | MemberDef *md;␊ |
7074 | for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name␊ |
7075 | {␊ |
7076 | MemberDef *bmd = mn->first(); // for each other member with the same name␊ |
7077 | while (bmd)␊ |
7078 | {␊ |
7079 | ClassDef *mcd = md->getClassDef();␊ |
7080 | if (mcd && mcd->baseClasses())␊ |
7081 | {␊ |
7082 | ClassDef *bmcd = bmd->getClassDef();␊ |
7083 | //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",␊ |
7084 | // mcd->name().data(),md->name().data(),md,␊ |
7085 | // bmcd->name().data(),bmd->name().data(),bmd␊ |
7086 | // );␊ |
7087 | if (md!=bmd && bmcd && mcd && bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE))␊ |
7088 | {␊ |
7089 | //printf(" derived scope\n");␊ |
7090 | LockingPtr<ArgumentList> bmdAl = bmd->argumentList();␊ |
7091 | LockingPtr<ArgumentList> mdAl = md->argumentList();␊ |
7092 | //printf(" Base argList=`%s'\n Super argList=`%s'\n",␊ |
7093 | // argListToString(bmdAl.pointer()).data(),␊ |
7094 | // argListToString(mdAl.pointer()).data()␊ |
7095 | // );␊ |
7096 | if ( ␊ |
7097 | matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(),␊ |
7098 | md->getOuterScope(), md->getFileDef(), mdAl.pointer(),␊ |
7099 | TRUE␊ |
7100 | ) ␊ |
7101 | )␊ |
7102 | {␊ |
7103 | //printf(" match found!\n");␊ |
7104 | if (mcd && bmcd && ␊ |
7105 | mcd->isLinkable() && bmcd->isLinkable()␊ |
7106 | )␊ |
7107 | {␊ |
7108 | MemberDef *rmd;␊ |
7109 | if ((rmd=md->reimplements())==0 ||␊ |
7110 | minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())␊ |
7111 | )␊ |
7112 | {␊ |
7113 | //printf("setting (new) reimplements member\n");␊ |
7114 | md->setReimplements(bmd);␊ |
7115 | }␊ |
7116 | //printf("%s: add reimplements member %s\n",mcd->name().data(),bmcd->name().data());␊ |
7117 | //md->setImplements(bmd);␊ |
7118 | //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());␊ |
7119 | bmd->insertReimplementedBy(md);␊ |
7120 | }␊ |
7121 | } ␊ |
7122 | }␊ |
7123 | }␊ |
7124 | bmd = mn->next();␊ |
7125 | }␊ |
7126 | }␊ |
7127 | } ␊ |
7128 | }␊ |
7129 | ␊ |
7130 | ␊ |
7131 | //----------------------------------------------------------------------------␊ |
7132 | //static void computeClassImplUsageRelations()␊ |
7133 | //{␊ |
7134 | // ClassDef *cd;␊ |
7135 | // ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
7136 | // for (;(cd=cli.current());++cli)␊ |
7137 | // {␊ |
7138 | // cd->determineImplUsageRelation();␊ |
7139 | // }␊ |
7140 | //}␊ |
7141 | ␊ |
7142 | //----------------------------------------------------------------------------␊ |
7143 | ␊ |
7144 | static void createTemplateInstanceMembers()␊ |
7145 | {␊ |
7146 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
7147 | ClassDef *cd;␊ |
7148 | // for each class␊ |
7149 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
7150 | {␊ |
7151 | // that is a template␊ |
7152 | QDict<ClassDef> *templInstances = cd->getTemplateInstances();␊ |
7153 | if (templInstances)␊ |
7154 | {␊ |
7155 | QDictIterator<ClassDef> qdi(*templInstances);␊ |
7156 | ClassDef *tcd=0;␊ |
7157 | // for each instance of the template␊ |
7158 | for (qdi.toFirst();(tcd=qdi.current());++qdi)␊ |
7159 | {␊ |
7160 | tcd->addMembersToTemplateInstance(cd,qdi.currentKey());␊ |
7161 | }␊ |
7162 | }␊ |
7163 | }␊ |
7164 | }␊ |
7165 | ␊ |
7166 | //----------------------------------------------------------------------------␊ |
7167 | ␊ |
7168 | // builds the list of all members for each class␊ |
7169 | ␊ |
7170 | static void buildCompleteMemberLists()␊ |
7171 | {␊ |
7172 | ClassDef *cd;␊ |
7173 | // merge members of categories into the class they extend␊ |
7174 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
7175 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
7176 | {␊ |
7177 | int i=cd->name().find('(');␊ |
7178 | if (i!=-1) // it is an Objective-C category␊ |
7179 | {␊ |
7180 | QCString baseName=cd->name().left(i);␊ |
7181 | ClassDef *baseClass=Doxygen::classSDict->find(baseName);␊ |
7182 | if (baseClass)␊ |
7183 | {␊ |
7184 | //printf("*** merging members of category %s into %s\n",␊ |
7185 | // cd->name().data(),baseClass->name().data());␊ |
7186 | baseClass->mergeCategory(cd);␊ |
7187 | }␊ |
7188 | }␊ |
7189 | }␊ |
7190 | // merge the member list of base classes into the inherited classes.␊ |
7191 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
7192 | {␊ |
7193 | if (// !cd->isReference() && // not an external class␊ |
7194 | cd->subClasses()==0 && // is a root of the hierarchy␊ |
7195 | cd->baseClasses()) // and has at least one base class␊ |
7196 | {␊ |
7197 | //printf("*** merging members for %s\n",cd->name().data());␊ |
7198 | cd->mergeMembers();␊ |
7199 | }␊ |
7200 | }␊ |
7201 | // now sort the member list of all classes.␊ |
7202 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
7203 | {␊ |
7204 | if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();␊ |
7205 | }␊ |
7206 | }␊ |
7207 | ␊ |
7208 | //----------------------------------------------------------------------------␊ |
7209 | ␊ |
7210 | static void generateFileSources()␊ |
7211 | {␊ |
7212 | if (documentedHtmlFiles==0) return;␊ |
7213 | if (Doxygen::inputNameList->count()>0)␊ |
7214 | {␊ |
7215 | FileNameListIterator fnli(*Doxygen::inputNameList); ␊ |
7216 | FileName *fn;␊ |
7217 | for (;(fn=fnli.current());++fnli)␊ |
7218 | {␊ |
7219 | FileNameIterator fni(*fn);␊ |
7220 | FileDef *fd;␊ |
7221 | for (;(fd=fni.current());++fni)␊ |
7222 | {␊ |
7223 | if (fd->generateSourceFile()) // sources need to be shown in the output␊ |
7224 | {␊ |
7225 | msg("Generating code for file %s...\n",fd->docName().data());␊ |
7226 | fd->writeSource(*g_outputList);␊ |
7227 | }␊ |
7228 | else if (!fd->isReference() && Doxygen::parseSourcesNeeded)␊ |
7229 | // we needed to parse the sources even if we do not show them␊ |
7230 | {␊ |
7231 | msg("Parsing code for file %s...\n",fd->docName().data());␊ |
7232 | fd->parseSource();␊ |
7233 | }␊ |
7234 | }␊ |
7235 | }␊ |
7236 | }␊ |
7237 | }␊ |
7238 | ␊ |
7239 | //----------------------------------------------------------------------------␊ |
7240 | ␊ |
7241 | static void generateFileDocs()␊ |
7242 | {␊ |
7243 | if (documentedHtmlFiles==0) return;␊ |
7244 | ␊ |
7245 | if (Doxygen::inputNameList->count()>0)␊ |
7246 | {␊ |
7247 | FileNameListIterator fnli(*Doxygen::inputNameList);␊ |
7248 | FileName *fn;␊ |
7249 | for (fnli.toFirst();(fn=fnli.current());++fnli)␊ |
7250 | {␊ |
7251 | FileNameIterator fni(*fn);␊ |
7252 | FileDef *fd;␊ |
7253 | for (fni.toFirst();(fd=fni.current());++fni)␊ |
7254 | {␊ |
7255 | bool doc = fd->isLinkableInProject();␊ |
7256 | if (doc)␊ |
7257 | {␊ |
7258 | msg("Generating docs for file %s...\n",fd->docName().data());␊ |
7259 | fd->writeDocumentation(*g_outputList);␊ |
7260 | }␊ |
7261 | }␊ |
7262 | }␊ |
7263 | }␊ |
7264 | }␊ |
7265 | ␊ |
7266 | //----------------------------------------------------------------------------␊ |
7267 | ␊ |
7268 | static void addSourceReferences()␊ |
7269 | {␊ |
7270 | // add source references for class definitions␊ |
7271 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
7272 | ClassDef *cd=0;␊ |
7273 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
7274 | {␊ |
7275 | FileDef *fd=cd->getBodyDef();␊ |
7276 | if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)␊ |
7277 | {␊ |
7278 | fd->addSourceRef(cd->getStartBodyLine(),cd,0);␊ |
7279 | }␊ |
7280 | }␊ |
7281 | // add source references for namespace definitions␊ |
7282 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
7283 | NamespaceDef *nd=0;␊ |
7284 | for (nli.toFirst();(nd=nli.current());++nli)␊ |
7285 | {␊ |
7286 | FileDef *fd=nd->getBodyDef();␊ |
7287 | if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)␊ |
7288 | {␊ |
7289 | fd->addSourceRef(nd->getStartBodyLine(),nd,0);␊ |
7290 | }␊ |
7291 | }␊ |
7292 | ␊ |
7293 | // add source references for member names␊ |
7294 | MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);␊ |
7295 | MemberName *mn=0;␊ |
7296 | for (mnli.toFirst();(mn=mnli.current());++mnli)␊ |
7297 | {␊ |
7298 | MemberNameIterator mni(*mn);␊ |
7299 | MemberDef *md=0;␊ |
7300 | for (mni.toFirst();(md=mni.current());++mni)␊ |
7301 | {␊ |
7302 | //printf("class member %s: def=%s body=%d link?=%d\n",␊ |
7303 | // md->name().data(),␊ |
7304 | // md->getBodyDef()?md->getBodyDef()->name().data():"<none>",␊ |
7305 | // md->getStartBodyLine(),md->isLinkableInProject());␊ |
7306 | FileDef *fd=md->getBodyDef();␊ |
7307 | if (fd && ␊ |
7308 | md->getStartBodyLine()!=-1 &&␊ |
7309 | md->isLinkableInProject() &&␊ |
7310 | (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)␊ |
7311 | )␊ |
7312 | {␊ |
7313 | //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",␊ |
7314 | // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); ␊ |
7315 | fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);␊ |
7316 | }␊ |
7317 | }␊ |
7318 | }␊ |
7319 | MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);␊ |
7320 | for (fnli.toFirst();(mn=fnli.current());++fnli)␊ |
7321 | {␊ |
7322 | MemberNameIterator mni(*mn);␊ |
7323 | MemberDef *md=0;␊ |
7324 | for (mni.toFirst();(md=mni.current());++mni)␊ |
7325 | {␊ |
7326 | FileDef *fd=md->getBodyDef();␊ |
7327 | //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",␊ |
7328 | // md->name().data(),␊ |
7329 | // md->getStartBodyLine(),md->getEndBodyLine(),fd,␊ |
7330 | // md->isLinkableInProject(),␊ |
7331 | // Doxygen::parseSourcesNeeded);␊ |
7332 | if (fd && ␊ |
7333 | md->getStartBodyLine()!=-1 && ␊ |
7334 | md->isLinkableInProject() && ␊ |
7335 | (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)␊ |
7336 | )␊ |
7337 | {␊ |
7338 | //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",␊ |
7339 | // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data()); ␊ |
7340 | fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);␊ |
7341 | } ␊ |
7342 | }␊ |
7343 | }␊ |
7344 | }␊ |
7345 | ␊ |
7346 | //----------------------------------------------------------------------------␊ |
7347 | ␊ |
7348 | static void sortMemberLists()␊ |
7349 | {␊ |
7350 | // sort class member lists␊ |
7351 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
7352 | ClassDef *cd=0;␊ |
7353 | for (cli.toFirst();(cd=cli.current());++cli)␊ |
7354 | {␊ |
7355 | cd->sortMemberLists();␊ |
7356 | }␊ |
7357 | ␊ |
7358 | // sort namespace member lists␊ |
7359 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
7360 | NamespaceDef *nd=0;␊ |
7361 | for (nli.toFirst();(nd=nli.current());++nli)␊ |
7362 | {␊ |
7363 | nd->sortMemberLists();␊ |
7364 | }␊ |
7365 | ␊ |
7366 | // sort file member lists␊ |
7367 | FileNameListIterator fnli(*Doxygen::inputNameList); ␊ |
7368 | FileName *fn;␊ |
7369 | for (;(fn=fnli.current());++fnli)␊ |
7370 | {␊ |
7371 | FileNameIterator fni(*fn);␊ |
7372 | FileDef *fd;␊ |
7373 | for (;(fd=fni.current());++fni)␊ |
7374 | {␊ |
7375 | fd->sortMemberLists();␊ |
7376 | }␊ |
7377 | }␊ |
7378 | ␊ |
7379 | // sort group member lists␊ |
7380 | GroupSDict::Iterator gli(*Doxygen::groupSDict);␊ |
7381 | GroupDef *gd;␊ |
7382 | for (gli.toFirst();(gd=gli.current());++gli)␊ |
7383 | {␊ |
7384 | gd->sortMemberLists();␊ |
7385 | }␊ |
7386 | }␊ |
7387 | ␊ |
7388 | //----------------------------------------------------------------------------␊ |
7389 | // generate the documentation of all classes␊ |
7390 | ␊ |
7391 | static void generateClassList(ClassSDict &classSDict)␊ |
7392 | {␊ |
7393 | ClassSDict::Iterator cli(classSDict);␊ |
7394 | for ( ; cli.current() ; ++cli )␊ |
7395 | {␊ |
7396 | ClassDef *cd=cli.current();␊ |
7397 | ␊ |
7398 | //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);␊ |
7399 | if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file␊ |
7400 | cd->getOuterScope()==Doxygen::globalScope // only look at global classes␊ |
7401 | ) && !cd->isHidden() && !cd->isEmbeddedInGroupDocs()␊ |
7402 | ) ␊ |
7403 | {␊ |
7404 | // skip external references, anonymous compounds and ␊ |
7405 | // template instances ␊ |
7406 | if ( cd->isLinkableInProject() && cd->templateMaster()==0)␊ |
7407 | {␊ |
7408 | msg("Generating docs for compound %s...\n",cd->name().data());␊ |
7409 | ␊ |
7410 | cd->writeDocumentation(*g_outputList);␊ |
7411 | cd->writeMemberList(*g_outputList);␊ |
7412 | }␊ |
7413 | // even for undocumented classes, the inner classes can be documented.␊ |
7414 | cd->writeDocumentationForInnerClasses(*g_outputList);␊ |
7415 | }␊ |
7416 | }␊ |
7417 | }␊ |
7418 | ␊ |
7419 | static void generateClassDocs()␊ |
7420 | {␊ |
7421 | // write the installdox script if necessary␊ |
7422 | if (Config_getBool("GENERATE_HTML") && ␊ |
7423 | (Config_getList("TAGFILES").count()>0 || ␊ |
7424 | Config_getBool("SEARCHENGINE")␊ |
7425 | )␊ |
7426 | ) ␊ |
7427 | {␊ |
7428 | writeInstallScript();␊ |
7429 | }␊ |
7430 | ␊ |
7431 | msg("Generating annotated compound index...\n");␊ |
7432 | writeAnnotatedIndex(*g_outputList);␊ |
7433 | ␊ |
7434 | //if (Config_getBool("ALPHABETICAL_INDEX"))␊ |
7435 | //{␊ |
7436 | msg("Generating alphabetical compound index...\n");␊ |
7437 | writeAlphabeticalIndex(*g_outputList);␊ |
7438 | //}␊ |
7439 | ␊ |
7440 | msg("Generating hierarchical class index...\n");␊ |
7441 | writeHierarchicalIndex(*g_outputList);␊ |
7442 | ␊ |
7443 | msg("Generating member index...\n");␊ |
7444 | writeClassMemberIndex(*g_outputList);␊ |
7445 | ␊ |
7446 | if (Doxygen::exampleSDict->count()>0)␊ |
7447 | {␊ |
7448 | msg("Generating example index...\n");␊ |
7449 | }␊ |
7450 | ␊ |
7451 | generateClassList(*Doxygen::classSDict);␊ |
7452 | generateClassList(*Doxygen::hiddenClasses);␊ |
7453 | }␊ |
7454 | ␊ |
7455 | //----------------------------------------------------------------------------␊ |
7456 | ␊ |
7457 | static void inheritDocumentation()␊ |
7458 | {␊ |
7459 | MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);␊ |
7460 | MemberName *mn;␊ |
7461 | //int count=0;␊ |
7462 | for (;(mn=mnli.current());++mnli)␊ |
7463 | {␊ |
7464 | MemberNameIterator mni(*mn);␊ |
7465 | MemberDef *md;␊ |
7466 | for (;(md=mni.current());++mni)␊ |
7467 | {␊ |
7468 | //printf("%04d Member `%s'\n",count++,md->name().data());␊ |
7469 | if (md->documentation().isEmpty() && md->briefDescription().isEmpty())␊ |
7470 | { // no documentation yet␊ |
7471 | MemberDef *bmd = md->reimplements();␊ |
7472 | while (bmd && bmd->documentation().isEmpty() && ␊ |
7473 | bmd->briefDescription().isEmpty()␊ |
7474 | )␊ |
7475 | { // search up the inheritance tree for a documentation member␊ |
7476 | //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());␊ |
7477 | bmd = bmd->reimplements();␊ |
7478 | }␊ |
7479 | if (bmd) // copy the documentation from the reimplemented member␊ |
7480 | {␊ |
7481 | md->setInheritsDocsFrom(bmd);␊ |
7482 | md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());␊ |
7483 | md->setDocsForDefinition(bmd->isDocsForDefinition());␊ |
7484 | md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());␊ |
7485 | md->copyArgumentNames(bmd);␊ |
7486 | md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());␊ |
7487 | }␊ |
7488 | }␊ |
7489 | }␊ |
7490 | }␊ |
7491 | }␊ |
7492 | ␊ |
7493 | //----------------------------------------------------------------------------␊ |
7494 | ␊ |
7495 | static void combineUsingRelations()␊ |
7496 | {␊ |
7497 | // for each file␊ |
7498 | FileNameListIterator fnli(*Doxygen::inputNameList);␊ |
7499 | FileName *fn;␊ |
7500 | for (fnli.toFirst();(fn=fnli.current());++fnli)␊ |
7501 | {␊ |
7502 | FileNameIterator fni(*fn);␊ |
7503 | FileDef *fd;␊ |
7504 | for (fni.toFirst();(fd=fni.current());++fni)␊ |
7505 | {␊ |
7506 | fd->visited=FALSE;␊ |
7507 | }␊ |
7508 | }␊ |
7509 | for (fnli.toFirst();(fn=fnli.current());++fnli)␊ |
7510 | {␊ |
7511 | FileNameIterator fni(*fn);␊ |
7512 | FileDef *fd;␊ |
7513 | for (fni.toFirst();(fd=fni.current());++fni)␊ |
7514 | {␊ |
7515 | fd->combineUsingRelations();␊ |
7516 | }␊ |
7517 | }␊ |
7518 | ␊ |
7519 | // for each namespace␊ |
7520 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
7521 | NamespaceDef *nd;␊ |
7522 | for (nli.toFirst() ; (nd=nli.current()) ; ++nli )␊ |
7523 | {␊ |
7524 | nd->visited=FALSE;␊ |
7525 | }␊ |
7526 | for (nli.toFirst() ; (nd=nli.current()) ; ++nli )␊ |
7527 | {␊ |
7528 | nd->combineUsingRelations();␊ |
7529 | }␊ |
7530 | }␊ |
7531 | ␊ |
7532 | //----------------------------------------------------------------------------␊ |
7533 | ␊ |
7534 | static void addMembersToMemberGroup()␊ |
7535 | {␊ |
7536 | // for each class␊ |
7537 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
7538 | ClassDef *cd;␊ |
7539 | for ( ; (cd=cli.current()) ; ++cli )␊ |
7540 | {␊ |
7541 | cd->addMembersToMemberGroup();␊ |
7542 | }␊ |
7543 | // for each file␊ |
7544 | FileName *fn=Doxygen::inputNameList->first();␊ |
7545 | while (fn)␊ |
7546 | {␊ |
7547 | FileDef *fd=fn->first();␊ |
7548 | while (fd)␊ |
7549 | {␊ |
7550 | fd->addMembersToMemberGroup();␊ |
7551 | fd=fn->next();␊ |
7552 | }␊ |
7553 | fn=Doxygen::inputNameList->next();␊ |
7554 | }␊ |
7555 | // for each namespace␊ |
7556 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
7557 | NamespaceDef *nd;␊ |
7558 | for ( ; (nd=nli.current()) ; ++nli )␊ |
7559 | {␊ |
7560 | nd->addMembersToMemberGroup();␊ |
7561 | }␊ |
7562 | // for each group␊ |
7563 | GroupSDict::Iterator gli(*Doxygen::groupSDict);␊ |
7564 | GroupDef *gd;␊ |
7565 | for (gli.toFirst();(gd=gli.current());++gli)␊ |
7566 | {␊ |
7567 | gd->addMembersToMemberGroup();␊ |
7568 | }␊ |
7569 | }␊ |
7570 | ␊ |
7571 | //----------------------------------------------------------------------------␊ |
7572 | ␊ |
7573 | static void distributeMemberGroupDocumentation()␊ |
7574 | {␊ |
7575 | // for each class␊ |
7576 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
7577 | ClassDef *cd;␊ |
7578 | for ( ; (cd=cli.current()) ; ++cli )␊ |
7579 | {␊ |
7580 | cd->distributeMemberGroupDocumentation();␊ |
7581 | }␊ |
7582 | // for each file␊ |
7583 | FileName *fn=Doxygen::inputNameList->first();␊ |
7584 | while (fn)␊ |
7585 | {␊ |
7586 | FileDef *fd=fn->first();␊ |
7587 | while (fd)␊ |
7588 | {␊ |
7589 | fd->distributeMemberGroupDocumentation();␊ |
7590 | fd=fn->next();␊ |
7591 | }␊ |
7592 | fn=Doxygen::inputNameList->next();␊ |
7593 | }␊ |
7594 | // for each namespace␊ |
7595 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
7596 | NamespaceDef *nd;␊ |
7597 | for ( ; (nd=nli.current()) ; ++nli )␊ |
7598 | {␊ |
7599 | nd->distributeMemberGroupDocumentation();␊ |
7600 | }␊ |
7601 | // for each group␊ |
7602 | GroupSDict::Iterator gli(*Doxygen::groupSDict);␊ |
7603 | GroupDef *gd;␊ |
7604 | for (gli.toFirst();(gd=gli.current());++gli)␊ |
7605 | {␊ |
7606 | gd->distributeMemberGroupDocumentation();␊ |
7607 | }␊ |
7608 | }␊ |
7609 | ␊ |
7610 | //----------------------------------------------------------------------------␊ |
7611 | ␊ |
7612 | static void findSectionsInDocumentation()␊ |
7613 | {␊ |
7614 | // for each class␊ |
7615 | ClassSDict::Iterator cli(*Doxygen::classSDict);␊ |
7616 | ClassDef *cd;␊ |
7617 | for ( ; (cd=cli.current()) ; ++cli )␊ |
7618 | {␊ |
7619 | cd->findSectionsInDocumentation();␊ |
7620 | }␊ |
7621 | // for each file␊ |
7622 | FileName *fn=Doxygen::inputNameList->first();␊ |
7623 | while (fn)␊ |
7624 | {␊ |
7625 | FileDef *fd=fn->first();␊ |
7626 | while (fd)␊ |
7627 | {␊ |
7628 | fd->findSectionsInDocumentation();␊ |
7629 | fd=fn->next();␊ |
7630 | }␊ |
7631 | fn=Doxygen::inputNameList->next();␊ |
7632 | }␊ |
7633 | // for each namespace␊ |
7634 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
7635 | NamespaceDef *nd;␊ |
7636 | for ( ; (nd=nli.current()) ; ++nli )␊ |
7637 | {␊ |
7638 | nd->findSectionsInDocumentation();␊ |
7639 | }␊ |
7640 | // for each group␊ |
7641 | GroupSDict::Iterator gli(*Doxygen::groupSDict);␊ |
7642 | GroupDef *gd;␊ |
7643 | for (gli.toFirst();(gd=gli.current());++gli)␊ |
7644 | {␊ |
7645 | gd->findSectionsInDocumentation();␊ |
7646 | }␊ |
7647 | // for each page␊ |
7648 | PageSDict::Iterator pdi(*Doxygen::pageSDict);␊ |
7649 | PageDef *pd=0;␊ |
7650 | for (pdi.toFirst();(pd=pdi.current());++pdi)␊ |
7651 | {␊ |
7652 | pd->findSectionsInDocumentation();␊ |
7653 | }␊ |
7654 | if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();␊ |
7655 | }␊ |
7656 | ␊ |
7657 | static void flushCachedTemplateRelations()␊ |
7658 | {␊ |
7659 | // remove all references to classes from the cache␊ |
7660 | // as there can be new template instances in the inheritance path␊ |
7661 | // to this class. Optimization: only remove those classes that␊ |
7662 | // have inheritance instances as direct or indirect sub classes.␊ |
7663 | QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);␊ |
7664 | LookupInfo *li=0;␊ |
7665 | for (ci.toFirst();(li=ci.current());++ci)␊ |
7666 | {␊ |
7667 | if (li->classDef)␊ |
7668 | {␊ |
7669 | Doxygen::lookupCache.remove(ci.currentKey());␊ |
7670 | }␊ |
7671 | }␊ |
7672 | // remove all cached typedef resolutions whose target is a␊ |
7673 | // template class as this may now be a template instance␊ |
7674 | MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);␊ |
7675 | MemberName *fn;␊ |
7676 | for (;(fn=fnli.current());++fnli) // for each global function name␊ |
7677 | {␊ |
7678 | MemberNameIterator fni(*fn);␊ |
7679 | MemberDef *fmd;␊ |
7680 | for (;(fmd=fni.current());++fni) // for each function with that name␊ |
7681 | {␊ |
7682 | if (fmd->isTypedefValCached())␊ |
7683 | {␊ |
7684 | ClassDef *cd = fmd->getCachedTypedefVal();␊ |
7685 | if (cd->isTemplate()) fmd->invalidateTypedefValCache();␊ |
7686 | }␊ |
7687 | }␊ |
7688 | }␊ |
7689 | MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);␊ |
7690 | for (;(fn=mnli.current());++mnli) // for each class method name␊ |
7691 | {␊ |
7692 | MemberNameIterator mni(*fn);␊ |
7693 | MemberDef *fmd;␊ |
7694 | for (;(fmd=mni.current());++mni) // for each function with that name␊ |
7695 | {␊ |
7696 | if (fmd->isTypedefValCached())␊ |
7697 | {␊ |
7698 | ClassDef *cd = fmd->getCachedTypedefVal();␊ |
7699 | if (cd->isTemplate()) fmd->invalidateTypedefValCache();␊ |
7700 | }␊ |
7701 | }␊ |
7702 | }␊ |
7703 | }␊ |
7704 | ␊ |
7705 | //----------------------------------------------------------------------------␊ |
7706 | ␊ |
7707 | static void flushUnresolvedRelations()␊ |
7708 | {␊ |
7709 | // Remove all unresolved references to classes from the cache.␊ |
7710 | // This is needed before resolving the inheritance relations, since␊ |
7711 | // it would otherwise not find the inheritance relation␊ |
7712 | // for C in the example below, as B::I was already found to be unresolvable ␊ |
7713 | // (which is correct if you igore the inheritance relation between A and B).␊ |
7714 | // ␊ |
7715 | // class A { class I {} };␊ |
7716 | // class B : public A {};␊ |
7717 | // class C : public B::I {};␊ |
7718 | //␊ |
7719 | QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);␊ |
7720 | LookupInfo *li=0;␊ |
7721 | for (ci.toFirst();(li=ci.current());++ci)␊ |
7722 | {␊ |
7723 | if (li->classDef==0 && li->typeDef==0)␊ |
7724 | {␊ |
7725 | Doxygen::lookupCache.remove(ci.currentKey());␊ |
7726 | }␊ |
7727 | }␊ |
7728 | ␊ |
7729 | MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);␊ |
7730 | MemberName *fn;␊ |
7731 | for (;(fn=fnli.current());++fnli) // for each global function name␊ |
7732 | {␊ |
7733 | MemberNameIterator fni(*fn);␊ |
7734 | MemberDef *fmd;␊ |
7735 | for (;(fmd=fni.current());++fni) // for each function with that name␊ |
7736 | {␊ |
7737 | fmd->invalidateCachedArgumentTypes();␊ |
7738 | }␊ |
7739 | }␊ |
7740 | MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);␊ |
7741 | for (;(fn=mnli.current());++mnli) // for each class method name␊ |
7742 | {␊ |
7743 | MemberNameIterator mni(*fn);␊ |
7744 | MemberDef *fmd;␊ |
7745 | for (;(fmd=mni.current());++mni) // for each function with that name␊ |
7746 | {␊ |
7747 | fmd->invalidateCachedArgumentTypes();␊ |
7748 | }␊ |
7749 | }␊ |
7750 | ␊ |
7751 | }␊ |
7752 | ␊ |
7753 | //----------------------------------------------------------------------------␊ |
7754 | ␊ |
7755 | static void findDefineDocumentation(EntryNav *rootNav)␊ |
7756 | {␊ |
7757 | if ((rootNav->section()==Entry::DEFINEDOC_SEC ||␊ |
7758 | rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()␊ |
7759 | )␊ |
7760 | {␊ |
7761 | rootNav->loadEntry(g_storage);␊ |
7762 | Entry *root = rootNav->entry();␊ |
7763 | ␊ |
7764 | //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",␊ |
7765 | // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());␊ |
7766 | ␊ |
7767 | if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file␊ |
7768 | {␊ |
7769 | MemberDef *md=new MemberDef("<tagfile>",1,␊ |
7770 | "#define",root->name,root->args,0,␊ |
7771 | Public,Normal,FALSE,Member,MemberDef::Define,0,0);␊ |
7772 | md->setTagInfo(rootNav->tagInfo());␊ |
7773 | //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);␊ |
7774 | md->setFileDef(rootNav->parent()->fileDef());␊ |
7775 | //printf("Adding member=%s\n",md->name().data());␊ |
7776 | MemberName *mn;␊ |
7777 | if ((mn=Doxygen::functionNameSDict->find(root->name)))␊ |
7778 | {␊ |
7779 | mn->append(md);␊ |
7780 | }␊ |
7781 | else ␊ |
7782 | {␊ |
7783 | mn = new MemberName(root->name);␊ |
7784 | mn->append(md);␊ |
7785 | Doxygen::functionNameSDict->append(root->name,mn);␊ |
7786 | }␊ |
7787 | }␊ |
7788 | MemberName *mn=Doxygen::functionNameSDict->find(root->name);␊ |
7789 | if (mn)␊ |
7790 | {␊ |
7791 | int count=0;␊ |
7792 | MemberDef *md=mn->first();␊ |
7793 | while (md)␊ |
7794 | {␊ |
7795 | if (md->memberType()==MemberDef::Define) count++;␊ |
7796 | md=mn->next();␊ |
7797 | }␊ |
7798 | if (count==1)␊ |
7799 | {␊ |
7800 | md=mn->first();␊ |
7801 | while (md)␊ |
7802 | {␊ |
7803 | if (md->memberType()==MemberDef::Define)␊ |
7804 | {␊ |
7805 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
7806 | md->setDocsForDefinition(!root->proto);␊ |
7807 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
7808 | if (md->inbodyDocumentation().isEmpty())␊ |
7809 | {␊ |
7810 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
7811 | }␊ |
7812 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
7813 | md->setBodyDef(rootNav->fileDef());␊ |
7814 | md->addSectionsToDefinition(root->anchors);␊ |
7815 | md->setMaxInitLines(root->initLines);␊ |
7816 | md->setRefItems(root->sli);␊ |
7817 | if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);␊ |
7818 | addMemberToGroups(root,md);␊ |
7819 | }␊ |
7820 | md=mn->next();␊ |
7821 | }␊ |
7822 | }␊ |
7823 | else if (count>1 && ␊ |
7824 | (!root->doc.isEmpty() || ␊ |
7825 | !root->brief.isEmpty() || ␊ |
7826 | root->bodyLine!=-1␊ |
7827 | )␊ |
7828 | ) ␊ |
7829 | // multiple defines don't know where to add docs␊ |
7830 | // but maybe they are in different files together with their documentation␊ |
7831 | {␊ |
7832 | md=mn->first();␊ |
7833 | while (md)␊ |
7834 | {␊ |
7835 | if (md->memberType()==MemberDef::Define)␊ |
7836 | {␊ |
7837 | FileDef *fd=md->getFileDef();␊ |
7838 | if (fd && fd->absFilePath()==root->fileName) ␊ |
7839 | // doc and define in the same file assume they belong together.␊ |
7840 | {␊ |
7841 | #if 0␊ |
7842 | if (md->documentation().isEmpty())␊ |
7843 | #endif␊ |
7844 | {␊ |
7845 | md->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
7846 | md->setDocsForDefinition(!root->proto);␊ |
7847 | }␊ |
7848 | #if 0␊ |
7849 | if (md->briefDescription().isEmpty())␊ |
7850 | #endif␊ |
7851 | {␊ |
7852 | md->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
7853 | }␊ |
7854 | if (md->inbodyDocumentation().isEmpty())␊ |
7855 | {␊ |
7856 | md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);␊ |
7857 | }␊ |
7858 | md->setBodySegment(root->bodyLine,root->endBodyLine);␊ |
7859 | md->setBodyDef(rootNav->fileDef());␊ |
7860 | md->addSectionsToDefinition(root->anchors);␊ |
7861 | md->setRefItems(root->sli);␊ |
7862 | if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);␊ |
7863 | addMemberToGroups(root,md);␊ |
7864 | }␊ |
7865 | }␊ |
7866 | md=mn->next();␊ |
7867 | }␊ |
7868 | //warn("warning: define %s found in the following files:\n",root->name.data());␊ |
7869 | //warn("Cannot determine where to add the documentation found "␊ |
7870 | // "at line %d of file %s. \n",␊ |
7871 | // root->startLine,root->fileName.data());␊ |
7872 | }␊ |
7873 | }␊ |
7874 | else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found␊ |
7875 | {␊ |
7876 | static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");␊ |
7877 | if (preEnabled)␊ |
7878 | {␊ |
7879 | warn(root->fileName,root->startLine,␊ |
7880 | "warning: documentation for unknown define %s found.\n",␊ |
7881 | root->name.data()␊ |
7882 | );␊ |
7883 | }␊ |
7884 | else␊ |
7885 | {␊ |
7886 | warn(root->fileName,root->startLine,␊ |
7887 | "warning: found documented #define but ignoring it because "␊ |
7888 | "ENABLE_PREPROCESSING is NO.\n",␊ |
7889 | root->name.data()␊ |
7890 | );␊ |
7891 | }␊ |
7892 | }␊ |
7893 | ␊ |
7894 | rootNav->releaseEntry();␊ |
7895 | }␊ |
7896 | RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);␊ |
7897 | }␊ |
7898 | ␊ |
7899 | //----------------------------------------------------------------------------␊ |
7900 | ␊ |
7901 | static void findDirDocumentation(EntryNav *rootNav)␊ |
7902 | {␊ |
7903 | if (rootNav->section() == Entry::DIRDOC_SEC)␊ |
7904 | {␊ |
7905 | rootNav->loadEntry(g_storage);␊ |
7906 | Entry *root = rootNav->entry();␊ |
7907 | ␊ |
7908 | QCString normalizedName = root->name;␊ |
7909 | normalizedName = substitute(normalizedName,"\\","/");␊ |
7910 | //printf("root->docFile=%s normalizedName=%s\n",␊ |
7911 | // root->docFile.data(),normalizedName.data());␊ |
7912 | if (root->docFile==normalizedName) // current dir?␊ |
7913 | {␊ |
7914 | int lastSlashPos=normalizedName.findRev('/'); ␊ |
7915 | if (lastSlashPos!=-1) // strip file name␊ |
7916 | {␊ |
7917 | normalizedName=normalizedName.left(lastSlashPos);␊ |
7918 | }␊ |
7919 | }␊ |
7920 | if (normalizedName.at(normalizedName.length()-1)!='/')␊ |
7921 | {␊ |
7922 | normalizedName+='/';␊ |
7923 | }␊ |
7924 | DirDef *dir,*matchingDir=0;␊ |
7925 | SDict<DirDef>::Iterator sdi(*Doxygen::directories);␊ |
7926 | for (sdi.toFirst();(dir=sdi.current());++sdi)␊ |
7927 | {␊ |
7928 | //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());␊ |
7929 | if (dir->name().right(normalizedName.length())==normalizedName)␊ |
7930 | {␊ |
7931 | if (matchingDir)␊ |
7932 | {␊ |
7933 | warn(root->fileName,root->startLine,␊ |
7934 | "warning: \\dir command matches multiple directories.\n"␊ |
7935 | " Applying the command for directory %s\n"␊ |
7936 | " Ignoring the command for directory %s\n",␊ |
7937 | matchingDir->name().data(),dir->name().data()␊ |
7938 | );␊ |
7939 | }␊ |
7940 | else␊ |
7941 | {␊ |
7942 | matchingDir=dir;␊ |
7943 | }␊ |
7944 | }␊ |
7945 | }␊ |
7946 | if (matchingDir)␊ |
7947 | {␊ |
7948 | //printf("Match for with dir %s\n",matchingDir->name().data());␊ |
7949 | matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);␊ |
7950 | matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);␊ |
7951 | matchingDir->setRefItems(root->sli);␊ |
7952 | addDirToGroups(root,matchingDir);␊ |
7953 | }␊ |
7954 | else␊ |
7955 | {␊ |
7956 | warn(root->fileName,root->startLine,"warning: No matching "␊ |
7957 | "directory found for command \\dir %s\n",normalizedName.data());␊ |
7958 | }␊ |
7959 | rootNav->releaseEntry();␊ |
7960 | }␊ |
7961 | RECURSE_ENTRYTREE(findDirDocumentation,rootNav);␊ |
7962 | }␊ |
7963 | ␊ |
7964 | ␊ |
7965 | //----------------------------------------------------------------------------␊ |
7966 | // create a (sorted) list of separate documentation pages␊ |
7967 | ␊ |
7968 | static void buildPageList(EntryNav *rootNav)␊ |
7969 | {␊ |
7970 | if (rootNav->section() == Entry::PAGEDOC_SEC)␊ |
7971 | {␊ |
7972 | rootNav->loadEntry(g_storage);␊ |
7973 | Entry *root = rootNav->entry();␊ |
7974 | ␊ |
7975 | if (!root->name.isEmpty())␊ |
7976 | {␊ |
7977 | addRelatedPage(rootNav);␊ |
7978 | }␊ |
7979 | ␊ |
7980 | rootNav->releaseEntry();␊ |
7981 | }␊ |
7982 | else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)␊ |
7983 | {␊ |
7984 | rootNav->loadEntry(g_storage);␊ |
7985 | Entry *root = rootNav->entry();␊ |
7986 | ␊ |
7987 | QCString title=root->args.stripWhiteSpace();␊ |
7988 | if (title.isEmpty()) title=theTranslator->trMainPage();␊ |
7989 | QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";␊ |
7990 | addRefItem(root->sli,␊ |
7991 | name,␊ |
7992 | "page",␊ |
7993 | name,␊ |
7994 | title,␊ |
7995 | 0␊ |
7996 | );␊ |
7997 | ␊ |
7998 | rootNav->releaseEntry();␊ |
7999 | }␊ |
8000 | RECURSE_ENTRYTREE(buildPageList,rootNav);␊ |
8001 | }␊ |
8002 | ␊ |
8003 | static void findMainPage(EntryNav *rootNav)␊ |
8004 | {␊ |
8005 | if (rootNav->section() == Entry::MAINPAGEDOC_SEC)␊ |
8006 | {␊ |
8007 | rootNav->loadEntry(g_storage);␊ |
8008 | Entry *root = rootNav->entry();␊ |
8009 | ␊ |
8010 | if (Doxygen::mainPage==0)␊ |
8011 | {␊ |
8012 | //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());␊ |
8013 | QCString title=root->args.stripWhiteSpace();␊ |
8014 | QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";␊ |
8015 | Doxygen::mainPage = new PageDef(root->fileName,root->startLine,␊ |
8016 | indexName, root->brief+root->doc+root->inbodyDocs,title);␊ |
8017 | //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);␊ |
8018 | Doxygen::mainPage->setFileName(indexName);␊ |
8019 | addPageToContext(Doxygen::mainPage,rootNav);␊ |
8020 | ␊ |
8021 | // a page name is a label as well!␊ |
8022 | SectionInfo *si=new SectionInfo(␊ |
8023 | indexName,␊ |
8024 | Doxygen::mainPage->name(),␊ |
8025 | Doxygen::mainPage->title(),␊ |
8026 | SectionInfo::Page);␊ |
8027 | Doxygen::sectionDict.insert(indexName,si);␊ |
8028 | Doxygen::mainPage->addSectionsToDefinition(root->anchors);␊ |
8029 | }␊ |
8030 | else␊ |
8031 | {␊ |
8032 | warn(root->fileName,root->startLine,␊ |
8033 | "warning: found more than one \\mainpage comment block! Skipping this "␊ |
8034 | "block."␊ |
8035 | );␊ |
8036 | }␊ |
8037 | ␊ |
8038 | rootNav->releaseEntry();␊ |
8039 | }␊ |
8040 | RECURSE_ENTRYTREE(findMainPage,rootNav);␊ |
8041 | }␊ |
8042 | ␊ |
8043 | static void computePageRelations(EntryNav *rootNav)␊ |
8044 | {␊ |
8045 | if ((rootNav->section()==Entry::PAGEDOC_SEC || ␊ |
8046 | rootNav->section()==Entry::MAINPAGEDOC_SEC␊ |
8047 | )␊ |
8048 | && !rootNav->name().isEmpty()␊ |
8049 | )␊ |
8050 | {␊ |
8051 | rootNav->loadEntry(g_storage);␊ |
8052 | Entry *root = rootNav->entry();␊ |
8053 | ␊ |
8054 | PageDef *pd = root->section==Entry::PAGEDOC_SEC ?␊ |
8055 | Doxygen::pageSDict->find(root->name) : ␊ |
8056 | Doxygen::mainPage; ␊ |
8057 | if (pd)␊ |
8058 | {␊ |
8059 | QListIterator<BaseInfo> bii(*root->extends);␊ |
8060 | BaseInfo *bi;␊ |
8061 | for (bii.toFirst();(bi=bii.current());++bii)␊ |
8062 | {␊ |
8063 | PageDef *subPd = Doxygen::pageSDict->find(bi->name);␊ |
8064 | if (subPd)␊ |
8065 | {␊ |
8066 | pd->addInnerCompound(subPd);␊ |
8067 | //printf("*** Added subpage relation: %s->%s\n",␊ |
8068 | // pd->name().data(),subPd->name().data());␊ |
8069 | }␊ |
8070 | }␊ |
8071 | }␊ |
8072 | ␊ |
8073 | rootNav->releaseEntry();␊ |
8074 | }␊ |
8075 | RECURSE_ENTRYTREE(computePageRelations,rootNav);␊ |
8076 | }␊ |
8077 | ␊ |
8078 | static void checkPageRelations()␊ |
8079 | {␊ |
8080 | PageSDict::Iterator pdi(*Doxygen::pageSDict);␊ |
8081 | PageDef *pd=0;␊ |
8082 | for (pdi.toFirst();(pd=pdi.current());++pdi)␊ |
8083 | {␊ |
8084 | Definition *ppd = pd->getOuterScope();␊ |
8085 | while (ppd)␊ |
8086 | {␊ |
8087 | if (ppd==pd)␊ |
8088 | {␊ |
8089 | err("warning: page defined at line %d of file %s with label %s is a subpage "␊ |
8090 | "of itself! Please remove this cyclic dependency.\n",␊ |
8091 | pd->docLine(),pd->docFile().data(),pd->name().data());␊ |
8092 | exit(1);␊ |
8093 | }␊ |
8094 | ppd=ppd->getOuterScope();␊ |
8095 | }␊ |
8096 | }␊ |
8097 | }␊ |
8098 | ␊ |
8099 | //----------------------------------------------------------------------------␊ |
8100 | ␊ |
8101 | static void resolveUserReferences()␊ |
8102 | {␊ |
8103 | QDictIterator<SectionInfo> sdi(Doxygen::sectionDict);␊ |
8104 | SectionInfo *si;␊ |
8105 | for (;(si=sdi.current());++sdi)␊ |
8106 | {␊ |
8107 | //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",␊ |
8108 | // si->label.data(),si->definition?si->definition->name().data():"<none>",␊ |
8109 | // si->fileName.data());␊ |
8110 | PageDef *pd=0;␊ |
8111 | ␊ |
8112 | // hack: the items of a todo/test/bug/deprecated list are all fragments from ␊ |
8113 | // different files, so the resulting section's all have the wrong file ␊ |
8114 | // name (not from the todo/test/bug/deprecated list, but from the file in ␊ |
8115 | // which they are defined). We correct this here by looking at the ␊ |
8116 | // generated section labels!␊ |
8117 | QDictIterator<RefList> rli(*Doxygen::xrefLists);␊ |
8118 | RefList *rl;␊ |
8119 | for (rli.toFirst();(rl=rli.current());++rli)␊ |
8120 | {␊ |
8121 | QCString label="_"+rl->listName(); // "_todo", "_test", ...␊ |
8122 | if (si->label.left(label.length())==label)␊ |
8123 | {␊ |
8124 | si->fileName=rl->listName();␊ |
8125 | si->generated=TRUE;␊ |
8126 | break;␊ |
8127 | }␊ |
8128 | }␊ |
8129 | ␊ |
8130 | //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());␊ |
8131 | if (!si->generated)␊ |
8132 | {␊ |
8133 | // if this section is in a page and the page is in a group, then we␊ |
8134 | // have to adjust the link file name to point to the group.␊ |
8135 | if (!si->fileName.isEmpty() && ␊ |
8136 | (pd=Doxygen::pageSDict->find(si->fileName)) &&␊ |
8137 | pd->getGroupDef())␊ |
8138 | {␊ |
8139 | si->fileName=pd->getGroupDef()->getOutputFileBase().copy();␊ |
8140 | }␊ |
8141 | ␊ |
8142 | if (si->definition)␊ |
8143 | {␊ |
8144 | // TODO: there should be one function in Definition that returns␊ |
8145 | // the file to link to, so we can avoid the following tests.␊ |
8146 | GroupDef *gd=0;␊ |
8147 | if (si->definition->definitionType()==Definition::TypeMember)␊ |
8148 | {␊ |
8149 | gd = ((MemberDef *)si->definition)->getGroupDef();␊ |
8150 | }␊ |
8151 | ␊ |
8152 | if (gd)␊ |
8153 | {␊ |
8154 | si->fileName=gd->getOutputFileBase().copy();␊ |
8155 | }␊ |
8156 | else␊ |
8157 | {␊ |
8158 | //si->fileName=si->definition->getOutputFileBase().copy();␊ |
8159 | //printf("Setting si->fileName to %s\n",si->fileName.data());␊ |
8160 | }␊ |
8161 | }␊ |
8162 | }␊ |
8163 | //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());␊ |
8164 | }␊ |
8165 | }␊ |
8166 | ␊ |
8167 | ␊ |
8168 | //----------------------------------------------------------------------------␊ |
8169 | // generate all separate documentation pages␊ |
8170 | ␊ |
8171 | ␊ |
8172 | static void generatePageDocs()␊ |
8173 | {␊ |
8174 | //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());␊ |
8175 | if (documentedPages==0) return;␊ |
8176 | PageSDict::Iterator pdi(*Doxygen::pageSDict);␊ |
8177 | PageDef *pd=0;␊ |
8178 | for (pdi.toFirst();(pd=pdi.current());++pdi)␊ |
8179 | {␊ |
8180 | if (!pd->getGroupDef() && !pd->isReference())␊ |
8181 | {␊ |
8182 | msg("Generating docs for page %s...\n",pd->name().data());␊ |
8183 | Doxygen::insideMainPage=TRUE;␊ |
8184 | pd->writeDocumentation(*g_outputList);␊ |
8185 | Doxygen::insideMainPage=FALSE;␊ |
8186 | }␊ |
8187 | }␊ |
8188 | }␊ |
8189 | ␊ |
8190 | //----------------------------------------------------------------------------␊ |
8191 | // create a (sorted) list & dictionary of example pages␊ |
8192 | ␊ |
8193 | static void buildExampleList(EntryNav *rootNav)␊ |
8194 | {␊ |
8195 | if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty()) ␊ |
8196 | {␊ |
8197 | rootNav->loadEntry(g_storage);␊ |
8198 | Entry *root = rootNav->entry();␊ |
8199 | ␊ |
8200 | if (Doxygen::exampleSDict->find(root->name))␊ |
8201 | {␊ |
8202 | warn(root->fileName,root->startLine,␊ |
8203 | "warning: Example %s was already documented. Ignoring "␊ |
8204 | "documentation found here.",␊ |
8205 | root->name.data()␊ |
8206 | );␊ |
8207 | }␊ |
8208 | else␊ |
8209 | {␊ |
8210 | PageDef *pd=new PageDef(root->fileName,root->startLine,␊ |
8211 | root->name,root->brief+root->doc+root->inbodyDocs,root->args);␊ |
8212 | pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));␊ |
8213 | pd->addSectionsToDefinition(root->anchors);␊ |
8214 | //pi->addSections(root->anchors);␊ |
8215 | ␊ |
8216 | Doxygen::exampleSDict->inSort(root->name,pd);␊ |
8217 | //we don't add example to groups ␊ |
8218 | //addExampleToGroups(root,pd);␊ |
8219 | }␊ |
8220 | ␊ |
8221 | rootNav->releaseEntry();␊ |
8222 | }␊ |
8223 | RECURSE_ENTRYTREE(buildExampleList,rootNav);␊ |
8224 | }␊ |
8225 | ␊ |
8226 | //----------------------------------------------------------------------------␊ |
8227 | // prints the Entry tree (for debugging)␊ |
8228 | ␊ |
8229 | void printNavTree(EntryNav *rootNav,int indent)␊ |
8230 | {␊ |
8231 | QCString indentStr;␊ |
8232 | indentStr.fill(' ',indent);␊ |
8233 | msg("%s%s (sec=0x%x)\n",␊ |
8234 | indentStr.isEmpty()?"":indentStr.data(),␊ |
8235 | rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),␊ |
8236 | rootNav->section());␊ |
8237 | if (rootNav->children()) ␊ |
8238 | {␊ |
8239 | EntryNavListIterator eli(*rootNav->children());␊ |
8240 | for (;eli.current();++eli) printNavTree(eli.current(),indent+2);␊ |
8241 | }␊ |
8242 | }␊ |
8243 | ␊ |
8244 | ␊ |
8245 | //----------------------------------------------------------------------------␊ |
8246 | // generate the example documentation ␊ |
8247 | ␊ |
8248 | static void generateExampleDocs()␊ |
8249 | {␊ |
8250 | g_outputList->disable(OutputGenerator::Man);␊ |
8251 | PageSDict::Iterator pdi(*Doxygen::exampleSDict);␊ |
8252 | PageDef *pd=0;␊ |
8253 | for (pdi.toFirst();(pd=pdi.current());++pdi)␊ |
8254 | {␊ |
8255 | msg("Generating docs for example %s...\n",pd->name().data());␊ |
8256 | resetCCodeParserState();␊ |
8257 | QCString n=pd->getOutputFileBase();␊ |
8258 | startFile(*g_outputList,n,n,pd->name());␊ |
8259 | startTitle(*g_outputList,n);␊ |
8260 | g_outputList->docify(pd->name());␊ |
8261 | endTitle(*g_outputList,n,0);␊ |
8262 | g_outputList->startContents();␊ |
8263 | g_outputList->parseDoc(pd->docFile(), // file␊ |
8264 | pd->docLine(), // startLine␊ |
8265 | pd, // context␊ |
8266 | 0, // memberDef␊ |
8267 | pd->documentation()+"\n\n\\include "+pd->name(), // docs␊ |
8268 | TRUE, // index words␊ |
8269 | TRUE, // is example␊ |
8270 | pd->name()␊ |
8271 | );␊ |
8272 | g_outputList->endContents();␊ |
8273 | endFile(*g_outputList);␊ |
8274 | }␊ |
8275 | g_outputList->enable(OutputGenerator::Man);␊ |
8276 | }␊ |
8277 | ␊ |
8278 | //----------------------------------------------------------------------------␊ |
8279 | // generate module pages␊ |
8280 | ␊ |
8281 | static void generateGroupDocs()␊ |
8282 | {␊ |
8283 | GroupSDict::Iterator gli(*Doxygen::groupSDict);␊ |
8284 | GroupDef *gd;␊ |
8285 | for (gli.toFirst();(gd=gli.current());++gli)␊ |
8286 | {␊ |
8287 | if (!gd->isReference())␊ |
8288 | {␊ |
8289 | gd->writeDocumentation(*g_outputList);␊ |
8290 | }␊ |
8291 | }␊ |
8292 | }␊ |
8293 | ␊ |
8294 | //----------------------------------------------------------------------------␊ |
8295 | ␊ |
8296 | //static void generatePackageDocs()␊ |
8297 | //{␊ |
8298 | // writePackageIndex(*g_outputList);␊ |
8299 | // ␊ |
8300 | // if (Doxygen::packageDict.count()>0)␊ |
8301 | // {␊ |
8302 | // PackageSDict::Iterator pdi(Doxygen::packageDict);␊ |
8303 | // PackageDef *pd;␊ |
8304 | // for (pdi.toFirst();(pd=pdi.current());++pdi)␊ |
8305 | // {␊ |
8306 | // pd->writeDocumentation(*g_outputList);␊ |
8307 | // }␊ |
8308 | // }␊ |
8309 | //}␊ |
8310 | ␊ |
8311 | //----------------------------------------------------------------------------␊ |
8312 | // generate module pages␊ |
8313 | ␊ |
8314 | static void generateNamespaceDocs()␊ |
8315 | {␊ |
8316 | writeNamespaceIndex(*g_outputList);␊ |
8317 | ␊ |
8318 | NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);␊ |
8319 | NamespaceDef *nd;␊ |
8320 | // for each namespace...␊ |
8321 | for (;(nd=nli.current());++nli)␊ |
8322 | {␊ |
8323 | ␊ |
8324 | if (nd->isLinkableInProject())␊ |
8325 | {␊ |
8326 | msg("Generating docs for namespace %s\n",nd->name().data());␊ |
8327 | nd->writeDocumentation(*g_outputList);␊ |
8328 | }␊ |
8329 | ␊ |
8330 | // for each class in the namespace...␊ |
8331 | ClassSDict::Iterator cli(*nd->getClassSDict());␊ |
8332 | for ( ; cli.current() ; ++cli )␊ |
8333 | {␊ |
8334 | ClassDef *cd=cli.current();␊ |
8335 | if ( ( cd->isLinkableInProject() && ␊ |
8336 | cd->templateMaster()==0␊ |
8337 | ) // skip external references, anonymous compounds and ␊ |
8338 | // template instances and nested classes␊ |
8339 | && !cd->isHidden()␊ |
8340 | )␊ |
8341 | {␊ |
8342 | msg("Generating docs for compound %s...\n",cd->name().data());␊ |
8343 | ␊ |
8344 | cd->writeDocumentation(*g_outputList);␊ |
8345 | cd->writeMemberList(*g_outputList);␊ |
8346 | }␊ |
8347 | cd->writeDocumentationForInnerClasses(*g_outputList);␊ |
8348 | }␊ |
8349 | }␊ |
8350 | }␊ |
8351 | ␊ |
8352 | #if defined(_WIN32)␊ |
8353 | static QCString fixSlashes(QCString &s)␊ |
8354 | {␊ |
8355 | QCString result;␊ |
8356 | uint i;␊ |
8357 | for (i=0;i<s.length();i++)␊ |
8358 | {␊ |
8359 | switch(s.at(i))␊ |
8360 | {␊ |
8361 | case '/': ␊ |
8362 | case '\\': ␊ |
8363 | result+="\\\\"; ␊ |
8364 | break;␊ |
8365 | default:␊ |
8366 | result+=s.at(i);␊ |
8367 | }␊ |
8368 | }␊ |
8369 | return result;␊ |
8370 | }␊ |
8371 | #endif␊ |
8372 | ␊ |
8373 | ␊ |
8374 | //----------------------------------------------------------------------------␊ |
8375 | // generate files for the search engine␊ |
8376 | ␊ |
8377 | //static void generateSearchIndex()␊ |
8378 | //{␊ |
8379 | // if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTML"))␊ |
8380 | // {␊ |
8381 | // // create search index␊ |
8382 | // QCString fileName;␊ |
8383 | // writeSearchButton(Config_getString("HTML_OUTPUT"));␊ |
8384 | //␊ |
8385 | //#if !defined(_WIN32)␊ |
8386 | // // create cgi script␊ |
8387 | // fileName = Config_getString("HTML_OUTPUT")+"/"+Config_getString("CGI_NAME");␊ |
8388 | // QFile f(fileName);␊ |
8389 | // if (f.open(IO_WriteOnly))␊ |
8390 | // {␊ |
8391 | // QTextStream t(&f);␊ |
8392 | // t << "#!/bin/sh" << endl␊ |
8393 | // << "DOXYSEARCH=" << Config_getString("BIN_ABSPATH") << "/doxysearch" << endl␊ |
8394 | // << "DOXYPATH=\"" << Config_getString("DOC_ABSPATH") << " ";␊ |
8395 | //␊ |
8396 | // QStrList &extDocPaths=Config_getList("EXT_DOC_PATHS");␊ |
8397 | // char *s= extDocPaths.first();␊ |
8398 | // while (s)␊ |
8399 | // {␊ |
8400 | // t << s << " ";␊ |
8401 | // s=extDocPaths.next();␊ |
8402 | // }␊ |
8403 | //␊ |
8404 | // t << "\"" << endl ␊ |
8405 | // << "if [ -f $DOXYSEARCH ]" << endl␊ |
8406 | // << "then" << endl␊ |
8407 | // << " $DOXYSEARCH $DOXYPATH" << endl ␊ |
8408 | // << "else" << endl␊ |
8409 | // << " echo \"Content-Type: text/html\"" << endl␊ |
8410 | // << " echo \"\"" << endl␊ |
8411 | // << " echo \"<h2>error: $DOXYSEARCH not found. Check cgi script!</h2>\"" << endl␊ |
8412 | // << "fi" << endl;␊ |
8413 | //␊ |
8414 | // f.close();␊ |
8415 | // struct stat stat_struct;␊ |
8416 | // stat(fileName,&stat_struct);␊ |
8417 | // chmod(fileName,stat_struct.st_mode|S_IXUSR|S_IXGRP|S_IXOTH);␊ |
8418 | // }␊ |
8419 | // else␊ |
8420 | // {␊ |
8421 | // err("error: Cannot open file %s for writing\n",fileName.data());␊ |
8422 | // }␊ |
8423 | //#else /* Windows platform */␊ |
8424 | // // create cgi program␊ |
8425 | // fileName = Config_getString("CGI_NAME").copy();␊ |
8426 | // if (fileName.right(4)==".cgi") ␊ |
8427 | // fileName=fileName.left(fileName.length()-4);␊ |
8428 | // fileName+=".c";␊ |
8429 | // fileName.prepend(Config_getString("HTML_OUTPUT")+"/");␊ |
8430 | // QFile f(fileName);␊ |
8431 | // if (f.open(IO_WriteOnly))␊ |
8432 | // {␊ |
8433 | // QTextStream t(&f);␊ |
8434 | // t << "#include <stdio.h>" << endl;␊ |
8435 | // t << "#include <stdlib.h>" << endl;␊ |
8436 | // t << "#include <process.h>" << endl;␊ |
8437 | // t << endl;␊ |
8438 | // t << "const char *DOXYSEARCH = \"" << ␊ |
8439 | // fixSlashes(Config_getString("BIN_ABSPATH")) << "\\\\doxysearch.exe\";" << endl;␊ |
8440 | // t << "const char *DOXYPATH = \"" << ␊ |
8441 | // fixSlashes(Config_getString("DOC_ABSPATH")) << "\";" << endl;␊ |
8442 | // t << endl;␊ |
8443 | // t << "int main(void)" << endl;␊ |
8444 | // t << "{" << endl;␊ |
8445 | // t << " char buf[1024];" << endl;␊ |
8446 | // t << " sprintf(buf,\"%s %s\",DOXYSEARCH,DOXYPATH);" << endl; ␊ |
8447 | // t << " if (system(buf))" << endl;␊ |
8448 | // t << " {" << endl;␊ |
8449 | // t << " printf(\"Content-Type: text/html\\n\\n\");" << endl;␊ |
8450 | // t << " printf(\"<h2>error: failed to execute %s</h2>\\n\",DOXYSEARCH);" << endl;␊ |
8451 | // t << " exit(1);" << endl;␊ |
8452 | // t << " }" << endl;␊ |
8453 | // t << " return 0;" << endl;␊ |
8454 | // t << "}" << endl;␊ |
8455 | // f.close();␊ |
8456 | // }␊ |
8457 | // else␊ |
8458 | // {␊ |
8459 | // err("error: Cannot open file %s for writing\n",fileName.data());␊ |
8460 | // }␊ |
8461 | //#endif /* !defined(_WIN32) */␊ |
8462 | // ␊ |
8463 | // // create config file␊ |
8464 | // fileName = Config_getString("HTML_OUTPUT")+"/search.cfg";␊ |
8465 | // f.setName(fileName);␊ |
8466 | // if (f.open(IO_WriteOnly))␊ |
8467 | // {␊ |
8468 | // QTextStream t(&f);␊ |
8469 | // t << Config_getString("DOC_URL") << "/" << endl ␊ |
8470 | // << Config_getString("CGI_URL") << "/" << Config_getString("CGI_NAME") << endl;␊ |
8471 | // f.close();␊ |
8472 | // }␊ |
8473 | // else␊ |
8474 | // {␊ |
8475 | // err("error: Cannot open file %s for writing\n",fileName.data());␊ |
8476 | // }␊ |
8477 | // //g_outputList->generateExternalIndex();␊ |
8478 | // g_outputList->pushGeneratorState();␊ |
8479 | // g_outputList->disableAllBut(OutputGenerator::Html);␊ |
8480 | // startFile(*g_outputList,"header"+Doxygen::htmlFileExtension,0,"Search Engine",TRUE);␊ |
8481 | // g_outputList->endPlainFile();␊ |
8482 | // g_outputList->startPlainFile("footer"+Doxygen::htmlFileExtension);␊ |
8483 | // endFile(*g_outputList,TRUE);␊ |
8484 | // g_outputList->popGeneratorState();␊ |
8485 | // }␊ |
8486 | //}␊ |
8487 | ␊ |
8488 | //----------------------------------------------------------------------------␊ |
8489 | ␊ |
8490 | static bool openOutputFile(const char *outFile,QFile &f)␊ |
8491 | {␊ |
8492 | bool fileOpened=FALSE;␊ |
8493 | bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');␊ |
8494 | if (writeToStdout) // write to stdout␊ |
8495 | {␊ |
8496 | fileOpened = f.open(IO_WriteOnly,stdout);␊ |
8497 | }␊ |
8498 | else // write to file␊ |
8499 | {␊ |
8500 | QFileInfo fi(outFile);␊ |
8501 | if (fi.exists()) // create a backup␊ |
8502 | {␊ |
8503 | QDir dir=fi.dir();␊ |
8504 | QFileInfo backup(fi.fileName()+".bak");␊ |
8505 | if (backup.exists()) // remove existing backup␊ |
8506 | dir.remove(backup.fileName());␊ |
8507 | dir.rename(fi.fileName(),fi.fileName()+".bak");␊ |
8508 | } ␊ |
8509 | f.setName(outFile);␊ |
8510 | fileOpened = f.open(IO_WriteOnly|IO_Translate);␊ |
8511 | }␊ |
8512 | return fileOpened;␊ |
8513 | }␊ |
8514 | ␊ |
8515 | /*! Generate a template version of the configuration file.␊ |
8516 | * If the \a shortList parameter is TRUE a configuration file without␊ |
8517 | * comments will be generated.␊ |
8518 | */␊ |
8519 | static void generateConfigFile(const char *configFile,bool shortList,␊ |
8520 | bool updateOnly=FALSE)␊ |
8521 | {␊ |
8522 | QFile f;␊ |
8523 | bool fileOpened=openOutputFile(configFile,f);␊ |
8524 | bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');␊ |
8525 | if (fileOpened)␊ |
8526 | {␊ |
8527 | FTextStream t(&f);␊ |
8528 | Config::instance()->writeTemplate(t,shortList,updateOnly);␊ |
8529 | if (!writeToStdout)␊ |
8530 | {␊ |
8531 | if (!updateOnly)␊ |
8532 | {␊ |
8533 | msg("\n\nConfiguration file `%s' created.\n\n",configFile);␊ |
8534 | msg("Now edit the configuration file and enter\n\n");␊ |
8535 | if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile"))␊ |
8536 | msg(" doxygen %s\n\n",configFile);␊ |
8537 | else␊ |
8538 | msg(" doxygen\n\n");␊ |
8539 | msg("to generate the documentation for your project\n\n");␊ |
8540 | }␊ |
8541 | else␊ |
8542 | {␊ |
8543 | msg("\n\nConfiguration file `%s' updated.\n\n",configFile);␊ |
8544 | }␊ |
8545 | }␊ |
8546 | }␊ |
8547 | else␊ |
8548 | {␊ |
8549 | err("error: Cannot open file %s for writing\n",configFile);␊ |
8550 | exit(1);␊ |
8551 | }␊ |
8552 | }␊ |
8553 | ␊ |
8554 | //----------------------------------------------------------------------------␊ |
8555 | // read and parse a tag file␊ |
8556 | ␊ |
8557 | //static bool readLineFromFile(QFile &f,QCString &s)␊ |
8558 | //{␊ |
8559 | // char c=0;␊ |
8560 | // s.resize(0);␊ |
8561 | // while (!f.atEnd() && (c=f.getch())!='\n') s+=c;␊ |
8562 | // return f.atEnd();␊ |
8563 | //}␊ |
8564 | ␊ |
8565 | //----------------------------------------------------------------------------␊ |
8566 | ␊ |
8567 | static void readTagFile(Entry *root,const char *tl)␊ |
8568 | {␊ |
8569 | QCString tagLine = tl;␊ |
8570 | QCString fileName;␊ |
8571 | QCString destName;␊ |
8572 | int eqPos = tagLine.find('=');␊ |
8573 | if (eqPos!=-1) // tag command contains a destination␊ |
8574 | {␊ |
8575 | fileName = tagLine.left(eqPos).stripWhiteSpace();␊ |
8576 | destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();␊ |
8577 | QFileInfo fi(fileName);␊ |
8578 | Doxygen::tagDestinationDict.insert(fi.fileName(),new QCString(destName));␊ |
8579 | //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());␊ |
8580 | }␊ |
8581 | else␊ |
8582 | {␊ |
8583 | fileName = tagLine;␊ |
8584 | }␊ |
8585 | ␊ |
8586 | QFileInfo fi(fileName);␊ |
8587 | if (!fi.exists() || !fi.isFile())␊ |
8588 | {␊ |
8589 | err("error: Tag file `%s' does not exist or is not a file. Skipping it...\n",␊ |
8590 | fileName.data());␊ |
8591 | return;␊ |
8592 | }␊ |
8593 | ␊ |
8594 | if (!destName.isEmpty())␊ |
8595 | msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());␊ |
8596 | else␊ |
8597 | msg("Reading tag file `%s'...\n",fileName.data());␊ |
8598 | ␊ |
8599 | parseTagFile(root,fi.absFilePath(),fi.fileName());␊ |
8600 | ␊ |
8601 | }␊ |
8602 | ␊ |
8603 | //----------------------------------------------------------------------------␊ |
8604 | static void copyFile(const QCString &src,const QCString &dest)␊ |
8605 | {␊ |
8606 | QFile sf(src);␊ |
8607 | if (sf.open(IO_ReadOnly))␊ |
8608 | {␊ |
8609 | QFileInfo fi(src);␊ |
8610 | QFile df(dest);␊ |
8611 | if (df.open(IO_WriteOnly))␊ |
8612 | {␊ |
8613 | char *buffer = new char[fi.size()];␊ |
8614 | sf.readBlock(buffer,fi.size());␊ |
8615 | df.writeBlock(buffer,fi.size());␊ |
8616 | df.flush();␊ |
8617 | delete[] buffer;␊ |
8618 | }␊ |
8619 | else␊ |
8620 | {␊ |
8621 | err("error: could not write to file %s\n",dest.data());␊ |
8622 | }␊ |
8623 | }␊ |
8624 | else␊ |
8625 | {␊ |
8626 | err("error: could not open user specified file %s\n",src.data());␊ |
8627 | }␊ |
8628 | }␊ |
8629 | ␊ |
8630 | static void copyStyleSheet()␊ |
8631 | {␊ |
8632 | QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");␊ |
8633 | if (!htmlStyleSheet.isEmpty())␊ |
8634 | {␊ |
8635 | QFileInfo fi(htmlStyleSheet);␊ |
8636 | if (!fi.exists())␊ |
8637 | {␊ |
8638 | err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());␊ |
8639 | htmlStyleSheet.resize(0); // revert to the default␊ |
8640 | }␊ |
8641 | else␊ |
8642 | {␊ |
8643 | QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();␊ |
8644 | copyFile(htmlStyleSheet,destFileName);␊ |
8645 | }␊ |
8646 | }␊ |
8647 | }␊ |
8648 | ␊ |
8649 | static void copyLogo()␊ |
8650 | {␊ |
8651 | QCString &projectLogo = Config_getString("PROJECT_LOGO");␊ |
8652 | if (!projectLogo.isEmpty())␊ |
8653 | {␊ |
8654 | QFileInfo fi(projectLogo);␊ |
8655 | if (!fi.exists())␊ |
8656 | {␊ |
8657 | err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());␊ |
8658 | projectLogo.resize(0); // revert to the default␊ |
8659 | }␊ |
8660 | else␊ |
8661 | {␊ |
8662 | QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();␊ |
8663 | copyFile(projectLogo,destFileName);␊ |
8664 | }␊ |
8665 | }␊ |
8666 | }␊ |
8667 | ␊ |
8668 | static void copyExtraFiles()␊ |
8669 | {␊ |
8670 | QStrList files = Config_getList("HTML_EXTRA_FILES");␊ |
8671 | uint i;␊ |
8672 | for (i=0; i<files.count(); ++i)␊ |
8673 | {␊ |
8674 | QCString fileName(files.at(i));␊ |
8675 | ␊ |
8676 | if (!fileName.isEmpty())␊ |
8677 | {␊ |
8678 | QFileInfo fi(fileName);␊ |
8679 | if (!fi.exists()) ␊ |
8680 | {␊ |
8681 | err("Extra HTML file '%s' specified in HTML_EXTRA_FILES does not exist!\n", fileName.data());␊ |
8682 | }␊ |
8683 | else␊ |
8684 | {␊ |
8685 | QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();␊ |
8686 | Doxygen::indexList.addImageFile(fi.fileName().data());␊ |
8687 | copyFile(fileName, destFileName);␊ |
8688 | }␊ |
8689 | }␊ |
8690 | }␊ |
8691 | }␊ |
8692 | ␊ |
8693 | //! parse the list of input files␊ |
8694 | static void parseFiles(Entry *root,EntryNav *rootNav)␊ |
8695 | {␊ |
8696 | #if 0␊ |
8697 | void *cd = 0;␊ |
8698 | QCString inpEncoding = Config_getString("INPUT_ENCODING");␊ |
8699 | bool needsTranscoding = !inpEncoding.isEmpty();␊ |
8700 | if (needsTranscoding)␊ |
8701 | {␊ |
8702 | if (!(cd = portable_iconv_open("UTF-8", inpEncoding)))␊ |
8703 | {␊ |
8704 | err("error: unsupported character enconding: '%s'",inpEncoding.data());␊ |
8705 | exit(1);␊ |
8706 | }␊ |
8707 | }␊ |
8708 | #endif␊ |
8709 | ␊ |
8710 | QCString *s=g_inputFiles.first();␊ |
8711 | while (s)␊ |
8712 | {␊ |
8713 | QCString fileName=*s;␊ |
8714 | QCString extension;␊ |
8715 | int ei = fileName.findRev('.');␊ |
8716 | if (ei!=-1) extension=fileName.right(fileName.length()-ei);␊ |
8717 | ParserInterface *parser = Doxygen::parserManager->getParser(extension);␊ |
8718 | ␊ |
8719 | QFileInfo fi(fileName);␊ |
8720 | BufStr preBuf(fi.size()+4096);␊ |
8721 | ␊ |
8722 | if (Config_getBool("ENABLE_PREPROCESSING") && ␊ |
8723 | parser->needsPreprocessing(extension))␊ |
8724 | {␊ |
8725 | BufStr inBuf(fi.size()+4096);␊ |
8726 | msg("Preprocessing %s...\n",s->data());␊ |
8727 | readInputFile(fileName,inBuf);␊ |
8728 | preprocessFile(fileName,inBuf,preBuf);␊ |
8729 | }␊ |
8730 | else // no preprocessing␊ |
8731 | {␊ |
8732 | msg("Reading %s...\n",s->data());␊ |
8733 | readInputFile(fileName,preBuf);␊ |
8734 | }␊ |
8735 | ␊ |
8736 | BufStr convBuf(preBuf.curPos()+1024);␊ |
8737 | ␊ |
8738 | // convert multi-line C++ comments to C style comments␊ |
8739 | convertCppComments(&preBuf,&convBuf,fileName);␊ |
8740 | ␊ |
8741 | convBuf.addChar('\0');␊ |
8742 | ␊ |
8743 | // use language parse to parse the file␊ |
8744 | parser->parseInput(fileName,convBuf.data(),root);␊ |
8745 | ␊ |
8746 | // store the Entry tree in a file and create an index to␊ |
8747 | // navigate/load entries␊ |
8748 | bool ambig;␊ |
8749 | FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig);␊ |
8750 | ASSERT(fd!=0);␊ |
8751 | root->createNavigationIndex(rootNav,g_storage,fd);␊ |
8752 | ␊ |
8753 | s=g_inputFiles.next();␊ |
8754 | }␊ |
8755 | }␊ |
8756 | ␊ |
8757 | // resolves a path that may include symlinks, if a recursive symlink is␊ |
8758 | // found an empty string is returned.␊ |
8759 | static QCString resolveSymlink(QCString path)␊ |
8760 | {␊ |
8761 | int sepPos=0;␊ |
8762 | int oldPos=0;␊ |
8763 | QFileInfo fi;␊ |
8764 | QDict<void> nonSymlinks;␊ |
8765 | QDict<void> known;␊ |
8766 | QCString result = path;␊ |
8767 | QCString oldPrefix = "/";␊ |
8768 | do␊ |
8769 | {␊ |
8770 | #ifdef WIN32␊ |
8771 | // UNC path, skip server and share name␊ |
8772 | if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\")) ␊ |
8773 | sepPos = result.find('/',2);␊ |
8774 | if (sepPos!=-1) ␊ |
8775 | sepPos = result.find('/',sepPos+1);␊ |
8776 | #else␊ |
8777 | sepPos = result.find('/',sepPos+1);␊ |
8778 | #endif␊ |
8779 | QCString prefix = sepPos==-1 ? result : result.left(sepPos);␊ |
8780 | if (nonSymlinks.find(prefix)==0)␊ |
8781 | {␊ |
8782 | fi.setFile(prefix);␊ |
8783 | if (fi.isSymLink())␊ |
8784 | {␊ |
8785 | QString target = fi.readLink();␊ |
8786 | bool isRelative = QFileInfo(target).isRelative();␊ |
8787 | if (isRelative)␊ |
8788 | {␊ |
8789 | target = QDir::cleanDirPath(oldPrefix+"/"+target.data());␊ |
8790 | }␊ |
8791 | if (sepPos!=-1)␊ |
8792 | {␊ |
8793 | if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')␊ |
8794 | {␊ |
8795 | target+='/';␊ |
8796 | }␊ |
8797 | target+=result.mid(sepPos);␊ |
8798 | }␊ |
8799 | result = QDir::cleanDirPath(target).data();␊ |
8800 | sepPos = 0;␊ |
8801 | if (known.find(result)) return QCString(); // recursive symlink!␊ |
8802 | known.insert(result,(void*)0x8);␊ |
8803 | if (isRelative)␊ |
8804 | {␊ |
8805 | sepPos = oldPos;␊ |
8806 | }␊ |
8807 | else // link to absolute path␊ |
8808 | {␊ |
8809 | sepPos = 0;␊ |
8810 | oldPrefix = "/";␊ |
8811 | }␊ |
8812 | }␊ |
8813 | else␊ |
8814 | {␊ |
8815 | nonSymlinks.insert(prefix,(void*)0x8);␊ |
8816 | oldPrefix = prefix;␊ |
8817 | }␊ |
8818 | oldPos = sepPos;␊ |
8819 | }␊ |
8820 | }␊ |
8821 | while (sepPos!=-1);␊ |
8822 | return QDir::cleanDirPath(result).data();␊ |
8823 | }␊ |
8824 | ␊ |
8825 | static QDict<void> g_pathsVisited(1009);␊ |
8826 | ␊ |
8827 | //----------------------------------------------------------------------------␊ |
8828 | // Read all files matching at least one pattern in `patList' in the ␊ |
8829 | // directory represented by `fi'.␊ |
8830 | // The directory is read iff the recusiveFlag is set.␊ |
8831 | // The contents of all files is append to the input string␊ |
8832 | ␊ |
8833 | int readDir(QFileInfo *fi,␊ |
8834 | FileNameList *fnList,␊ |
8835 | FileNameDict *fnDict,␊ |
8836 | StringDict *exclDict,␊ |
8837 | QStrList *patList,␊ |
8838 | QStrList *exclPatList,␊ |
8839 | StringList *resultList,␊ |
8840 | StringDict *resultDict,␊ |
8841 | bool errorIfNotExist,␊ |
8842 | bool recursive,␊ |
8843 | QDict<void> *killDict␊ |
8844 | )␊ |
8845 | {␊ |
8846 | QString dirName = fi->absFilePath();␊ |
8847 | if (fi->isSymLink())␊ |
8848 | {␊ |
8849 | dirName = resolveSymlink(dirName.data());␊ |
8850 | if (dirName.isEmpty()) return 0; // recusive symlink␊ |
8851 | if (g_pathsVisited.find(dirName)) return 0; // already visited path␊ |
8852 | g_pathsVisited.insert(dirName,(void*)0x8);␊ |
8853 | }␊ |
8854 | QDir dir(dirName);␊ |
8855 | dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );␊ |
8856 | int totalSize=0;␊ |
8857 | msg("Searching for files in directory %s\n", fi->absFilePath().data());␊ |
8858 | //printf("killDict=%p count=%d\n",killDict,killDict->count());␊ |
8859 | ␊ |
8860 | const QFileInfoList *list = dir.entryInfoList();␊ |
8861 | if (list)␊ |
8862 | {␊ |
8863 | QFileInfoListIterator it( *list );␊ |
8864 | QFileInfo *cfi;␊ |
8865 | ␊ |
8866 | while ((cfi=it.current()))␊ |
8867 | {␊ |
8868 | if (exclDict==0 || exclDict->find(cfi->absFilePath())==0) ␊ |
8869 | { // file should not be excluded␊ |
8870 | //printf("killDict->find(%s)\n",cfi->absFilePath().data());␊ |
8871 | if (!cfi->exists() || !cfi->isReadable())␊ |
8872 | {␊ |
8873 | if (errorIfNotExist)␊ |
8874 | {␊ |
8875 | err("warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());␊ |
8876 | }␊ |
8877 | }␊ |
8878 | else if (cfi->isFile() && ␊ |
8879 | (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&␊ |
8880 | (patList==0 || patternMatch(*cfi,patList)) && ␊ |
8881 | !patternMatch(*cfi,exclPatList) &&␊ |
8882 | (killDict==0 || killDict->find(cfi->absFilePath())==0)␊ |
8883 | )␊ |
8884 | {␊ |
8885 | totalSize+=cfi->size()+cfi->absFilePath().length()+4;␊ |
8886 | QCString name=convertToQCString(cfi->fileName());␊ |
8887 | //printf("New file %s\n",name.data());␊ |
8888 | if (fnDict)␊ |
8889 | {␊ |
8890 | FileDef *fd=new FileDef(cfi->dirPath()+"/",name);␊ |
8891 | FileName *fn=0;␊ |
8892 | if (!name.isEmpty() && (fn=(*fnDict)[name]))␊ |
8893 | {␊ |
8894 | fn->append(fd);␊ |
8895 | }␊ |
8896 | else␊ |
8897 | {␊ |
8898 | fn = new FileName(cfi->absFilePath(),name);␊ |
8899 | fn->append(fd);␊ |
8900 | if (fnList) fnList->inSort(fn);␊ |
8901 | fnDict->insert(name,fn);␊ |
8902 | }␊ |
8903 | }␊ |
8904 | QCString *rs=0;␊ |
8905 | if (resultList || resultDict)␊ |
8906 | {␊ |
8907 | rs=new QCString(cfi->absFilePath());␊ |
8908 | }␊ |
8909 | if (resultList) resultList->append(rs);␊ |
8910 | if (resultDict) resultDict->insert(cfi->absFilePath(),rs);␊ |
8911 | if (killDict) killDict->insert(cfi->absFilePath(),(void *)0x8);␊ |
8912 | }␊ |
8913 | else if (recursive &&␊ |
8914 | (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&␊ |
8915 | cfi->isDir() && cfi->fileName()!="." && ␊ |
8916 | !patternMatch(*cfi,exclPatList) &&␊ |
8917 | cfi->fileName()!="..")␊ |
8918 | {␊ |
8919 | cfi->setFile(cfi->absFilePath());␊ |
8920 | totalSize+=readDir(cfi,fnList,fnDict,exclDict,␊ |
8921 | patList,exclPatList,resultList,resultDict,errorIfNotExist,␊ |
8922 | recursive,killDict);␊ |
8923 | }␊ |
8924 | }␊ |
8925 | ++it;␊ |
8926 | }␊ |
8927 | }␊ |
8928 | return totalSize;␊ |
8929 | }␊ |
8930 | ␊ |
8931 | ␊ |
8932 | //----------------------------------------------------------------------------␊ |
8933 | // read a file or all files in a directory and append their contents to the␊ |
8934 | // input string. The names of the files are appended to the `fiList' list.␊ |
8935 | ␊ |
8936 | int readFileOrDirectory(const char *s,␊ |
8937 | FileNameList *fnList,␊ |
8938 | FileNameDict *fnDict,␊ |
8939 | StringDict *exclDict,␊ |
8940 | QStrList *patList,␊ |
8941 | QStrList *exclPatList,␊ |
8942 | StringList *resultList,␊ |
8943 | StringDict *resultDict,␊ |
8944 | bool recursive,␊ |
8945 | bool errorIfNotExist,␊ |
8946 | QDict<void> *killDict␊ |
8947 | )␊ |
8948 | {␊ |
8949 | //printf("killDict=%p count=%d\n",killDict,killDict->count());␊ |
8950 | // strip trailing slashes␊ |
8951 | if (s==0) return 0;␊ |
8952 | QCString fs = s;␊ |
8953 | char lc = fs.at(fs.length()-1);␊ |
8954 | if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);␊ |
8955 | ␊ |
8956 | QFileInfo fi(fs);␊ |
8957 | //printf("readFileOrDirectory(%s)\n",s);␊ |
8958 | int totalSize=0;␊ |
8959 | {␊ |
8960 | if (exclDict==0 || exclDict->find(fi.absFilePath())==0)␊ |
8961 | {␊ |
8962 | if (!fi.exists() || !fi.isReadable())␊ |
8963 | {␊ |
8964 | if (errorIfNotExist)␊ |
8965 | {␊ |
8966 | err("warning: source %s is not a readable file or directory... skipping.\n",s);␊ |
8967 | }␊ |
8968 | }␊ |
8969 | else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())␊ |
8970 | {␊ |
8971 | if (fi.isFile())␊ |
8972 | {␊ |
8973 | //printf("killDict->find(%s)\n",fi.absFilePath().data());␊ |
8974 | if (killDict==0 || killDict->find(fi.absFilePath())==0)␊ |
8975 | {␊ |
8976 | totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input); ␊ |
8977 | //fiList->inSort(new FileInfo(fi));␊ |
8978 | QCString name=convertToQCString(fi.fileName());␊ |
8979 | //printf("New file %s\n",name.data());␊ |
8980 | if (fnDict)␊ |
8981 | {␊ |
8982 | FileDef *fd=new FileDef(fi.dirPath(TRUE)+"/",name);␊ |
8983 | FileName *fn=0;␊ |
8984 | if (!name.isEmpty() && (fn=(*fnDict)[name]))␊ |
8985 | {␊ |
8986 | fn->append(fd);␊ |
8987 | }␊ |
8988 | else␊ |
8989 | {␊ |
8990 | fn = new FileName(fi.absFilePath(),name);␊ |
8991 | fn->append(fd);␊ |
8992 | if (fnList) fnList->inSort(fn);␊ |
8993 | fnDict->insert(name,fn);␊ |
8994 | }␊ |
8995 | }␊ |
8996 | QCString *rs=0;␊ |
8997 | if (resultList || resultDict)␊ |
8998 | {␊ |
8999 | rs=new QCString(fi.absFilePath());␊ |
9000 | if (resultList) resultList->append(rs);␊ |
9001 | if (resultDict) resultDict->insert(fi.absFilePath(),rs);␊ |
9002 | }␊ |
9003 | ␊ |
9004 | if (killDict) killDict->insert(fi.absFilePath(),(void *)0x8);␊ |
9005 | }␊ |
9006 | }␊ |
9007 | else if (fi.isDir()) // readable dir␊ |
9008 | {␊ |
9009 | totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,␊ |
9010 | exclPatList,resultList,resultDict,errorIfNotExist,␊ |
9011 | recursive,killDict);␊ |
9012 | }␊ |
9013 | }␊ |
9014 | }␊ |
9015 | }␊ |
9016 | return totalSize;␊ |
9017 | }␊ |
9018 | ␊ |
9019 | //----------------------------------------------------------------------------␊ |
9020 | ␊ |
9021 | void readFormulaRepository()␊ |
9022 | {␊ |
9023 | QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");␊ |
9024 | if (f.open(IO_ReadOnly)) // open repository␊ |
9025 | {␊ |
9026 | msg("Reading formula repository...\n");␊ |
9027 | QTextStream t(&f);␊ |
9028 | QCString line;␊ |
9029 | while (!t.eof())␊ |
9030 | {␊ |
9031 | line=t.readLine();␊ |
9032 | int se=line.find(':'); // find name and text separator.␊ |
9033 | if (se==-1)␊ |
9034 | {␊ |
9035 | err("warning: formula.repository is corrupted!\n");␊ |
9036 | break;␊ |
9037 | }␊ |
9038 | else␊ |
9039 | {␊ |
9040 | QCString formName = line.left(se);␊ |
9041 | QCString formText = line.right(line.length()-se-1); ␊ |
9042 | Formula *f=new Formula(formText);␊ |
9043 | Doxygen::formulaList.append(f);␊ |
9044 | Doxygen::formulaDict.insert(formText,f);␊ |
9045 | Doxygen::formulaNameDict.insert(formName,f);␊ |
9046 | }␊ |
9047 | }␊ |
9048 | }␊ |
9049 | }␊ |
9050 | ␊ |
9051 | //----------------------------------------------------------------------------␊ |
9052 | ␊ |
9053 | static void expandAliases()␊ |
9054 | {␊ |
9055 | QDictIterator<QCString> adi(Doxygen::aliasDict);␊ |
9056 | QCString *s;␊ |
9057 | for (adi.toFirst();(s=adi.current());++adi)␊ |
9058 | {␊ |
9059 | *s = expandAlias(adi.currentKey(),*s);␊ |
9060 | }␊ |
9061 | }␊ |
9062 | ␊ |
9063 | //----------------------------------------------------------------------------␊ |
9064 | ␊ |
9065 | static void escapeAliases()␊ |
9066 | {␊ |
9067 | QDictIterator<QCString> adi(Doxygen::aliasDict);␊ |
9068 | QCString *s;␊ |
9069 | for (adi.toFirst();(s=adi.current());++adi)␊ |
9070 | {␊ |
9071 | QCString value=*s,newValue;␊ |
9072 | int in,p=0;␊ |
9073 | // for each \n in the alias command value␊ |
9074 | while ((in=value.find("\\n",p))!=-1)␊ |
9075 | {␊ |
9076 | newValue+=value.mid(p,in-p);␊ |
9077 | // expand \n's except if \n is part of a built-in command.␊ |
9078 | if (value.mid(in,5)!="\\note" && ␊ |
9079 | value.mid(in,5)!="\\name" && ␊ |
9080 | value.mid(in,10)!="\\namespace" && ␊ |
9081 | value.mid(in,14)!="\\nosubgrouping"␊ |
9082 | ) ␊ |
9083 | {␊ |
9084 | newValue+="\\_linebr ";␊ |
9085 | }␊ |
9086 | else ␊ |
9087 | {␊ |
9088 | newValue+="\\n";␊ |
9089 | }␊ |
9090 | p=in+2;␊ |
9091 | }␊ |
9092 | newValue+=value.mid(p,value.length()-p);␊ |
9093 | *s=newValue;␊ |
9094 | //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());␊ |
9095 | }␊ |
9096 | }␊ |
9097 | ␊ |
9098 | //----------------------------------------------------------------------------␊ |
9099 | ␊ |
9100 | void readAliases()␊ |
9101 | { ␊ |
9102 | // add aliases to a dictionary␊ |
9103 | Doxygen::aliasDict.setAutoDelete(TRUE);␊ |
9104 | QStrList &aliasList = Config_getList("ALIASES");␊ |
9105 | const char *s=aliasList.first();␊ |
9106 | while (s)␊ |
9107 | {␊ |
9108 | if (Doxygen::aliasDict[s]==0)␊ |
9109 | {␊ |
9110 | QCString alias=s;␊ |
9111 | int i=alias.find('=');␊ |
9112 | if (i>0)␊ |
9113 | {␊ |
9114 | QCString name=alias.left(i).stripWhiteSpace();␊ |
9115 | QCString value=alias.right(alias.length()-i-1);␊ |
9116 | //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data()); ␊ |
9117 | if (!name.isEmpty())␊ |
9118 | {␊ |
9119 | QCString *dn=Doxygen::aliasDict[name];␊ |
9120 | if (dn==0) // insert new alias␊ |
9121 | {␊ |
9122 | Doxygen::aliasDict.insert(name,new QCString(value));␊ |
9123 | }␊ |
9124 | else // overwrite previous alias␊ |
9125 | {␊ |
9126 | *dn=value;␊ |
9127 | }␊ |
9128 | }␊ |
9129 | }␊ |
9130 | }␊ |
9131 | s=aliasList.next();␊ |
9132 | }␊ |
9133 | expandAliases();␊ |
9134 | escapeAliases();␊ |
9135 | }␊ |
9136 | ␊ |
9137 | //----------------------------------------------------------------------------␊ |
9138 | ␊ |
9139 | static void dumpSymbol(FTextStream &t,Definition *d)␊ |
9140 | {␊ |
9141 | QCString anchor;␊ |
9142 | if (d->definitionType()==Definition::TypeMember)␊ |
9143 | {␊ |
9144 | MemberDef *md = (MemberDef *)d;␊ |
9145 | anchor=":"+md->anchor();␊ |
9146 | }␊ |
9147 | QCString scope;␊ |
9148 | if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope) ␊ |
9149 | {␊ |
9150 | scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;␊ |
9151 | }␊ |
9152 | t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"␊ |
9153 | << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"␊ |
9154 | << scope << "','"␊ |
9155 | << d->name() << "','"␊ |
9156 | << d->getDefFileName() << "','"␊ |
9157 | << d->getDefLine()␊ |
9158 | << "');" << endl;␊ |
9159 | }␊ |
9160 | ␊ |
9161 | static void dumpSymbolMap()␊ |
9162 | { ␊ |
9163 | QFile f("symbols.sql");␊ |
9164 | if (f.open(IO_WriteOnly))␊ |
9165 | {␊ |
9166 | FTextStream t(&f);␊ |
9167 | QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);␊ |
9168 | DefinitionIntf *intf;␊ |
9169 | for (;(intf=di.current());++di)␊ |
9170 | {␊ |
9171 | if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols␊ |
9172 | {␊ |
9173 | DefinitionListIterator dli(*(DefinitionList*)intf);␊ |
9174 | Definition *d;␊ |
9175 | // for each symbol␊ |
9176 | for (dli.toFirst();(d=dli.current());++dli)␊ |
9177 | {␊ |
9178 | dumpSymbol(t,d);␊ |
9179 | }␊ |
9180 | }␊ |
9181 | else // single symbol␊ |
9182 | {␊ |
9183 | Definition *d = (Definition *)intf;␊ |
9184 | if (d!=Doxygen::globalScope) dumpSymbol(t,d);␊ |
9185 | }␊ |
9186 | }␊ |
9187 | }␊ |
9188 | }␊ |
9189 | ␊ |
9190 | //----------------------------------------------------------------------------␊ |
9191 | ␊ |
9192 | void dumpConfigAsXML()␊ |
9193 | {␊ |
9194 | QFile f("config.xml");␊ |
9195 | if (f.open(IO_WriteOnly))␊ |
9196 | {␊ |
9197 | FTextStream t(&f);␊ |
9198 | Config::instance()->writeXML(t);␊ |
9199 | }␊ |
9200 | }␊ |
9201 | ␊ |
9202 | //----------------------------------------------------------------------------␊ |
9203 | // print the usage of doxygen␊ |
9204 | ␊ |
9205 | static void usage(const char *name)␊ |
9206 | {␊ |
9207 | msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2011\n\n",versionString);␊ |
9208 | msg("You can use doxygen in a number of ways:\n\n");␊ |
9209 | msg("1) Use doxygen to generate a template configuration file:\n");␊ |
9210 | msg(" %s [-s] -g [configName]\n\n",name);␊ |
9211 | msg(" If - is used for configName doxygen will write to standard output.\n\n");␊ |
9212 | msg("2) Use doxygen to update an old configuration file:\n");␊ |
9213 | msg(" %s [-s] -u [configName]\n\n",name);␊ |
9214 | msg("3) Use doxygen to generate documentation using an existing ");␊ |
9215 | msg("configuration file:\n");␊ |
9216 | msg(" %s [configName]\n\n",name);␊ |
9217 | msg(" If - is used for configName doxygen will read from standard input.\n\n");␊ |
9218 | msg("4) Use doxygen to generate a template file controlling the layout of the\n");␊ |
9219 | msg(" generated documentation:\n");␊ |
9220 | msg(" %s -l layoutFileName.xml\n\n",name);␊ |
9221 | msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");␊ |
9222 | msg(" RTF: %s -w rtf styleSheetFile\n",name);␊ |
9223 | msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);␊ |
9224 | msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);␊ |
9225 | msg("6) Use doxygen to generate an rtf extensions file\n");␊ |
9226 | msg(" RTF: %s -e rtf extensionsFile\n\n",name);␊ |
9227 | msg("If -s is specified the comments in the config file will be omitted.\n");␊ |
9228 | msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");␊ |
9229 | exit(1);␊ |
9230 | }␊ |
9231 | ␊ |
9232 | //----------------------------------------------------------------------------␊ |
9233 | // read the argument of option `c' from the comment argument list and␊ |
9234 | // update the option index `optind'.␊ |
9235 | ␊ |
9236 | static const char *getArg(int argc,char **argv,int &optind)␊ |
9237 | {␊ |
9238 | char *s=0;␊ |
9239 | if (strlen(&argv[optind][2])>0)␊ |
9240 | s=&argv[optind][2];␊ |
9241 | else if (optind+1<argc && argv[optind+1][0]!='-')␊ |
9242 | s=argv[++optind];␊ |
9243 | return s;␊ |
9244 | }␊ |
9245 | ␊ |
9246 | //----------------------------------------------------------------------------␊ |
9247 | ␊ |
9248 | extern void commentScanTest();␊ |
9249 | ␊ |
9250 | void initDoxygen()␊ |
9251 | {␊ |
9252 | setlocale(LC_ALL,"");␊ |
9253 | setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8␊ |
9254 | setlocale(LC_NUMERIC,"C");␊ |
9255 | ␊ |
9256 | //Doxygen::symbolMap->setAutoDelete(TRUE);␊ |
9257 | ␊ |
9258 | Doxygen::runningTime.start();␊ |
9259 | initPreprocessor();␊ |
9260 | ␊ |
9261 | Doxygen::parserManager = new ParserManager;␊ |
9262 | Doxygen::parserManager->registerParser("c", new CLanguageScanner, TRUE);␊ |
9263 | Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);␊ |
9264 | Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);␊ |
9265 | Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);␊ |
9266 | Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);␊ |
9267 | ␊ |
9268 | // register any additional parsers here...␊ |
9269 | ␊ |
9270 | initDefaultExtensionMapping();␊ |
9271 | initClassMemberIndices();␊ |
9272 | initNamespaceMemberIndices();␊ |
9273 | initFileMemberIndices();␊ |
9274 | ␊ |
9275 | Doxygen::symbolMap = new QDict<DefinitionIntf>(1000);␊ |
9276 | Doxygen::inputNameList = new FileNameList;␊ |
9277 | Doxygen::inputNameList->setAutoDelete(TRUE);␊ |
9278 | Doxygen::memberNameSDict = new MemberNameSDict(10000); ␊ |
9279 | Doxygen::memberNameSDict->setAutoDelete(TRUE);␊ |
9280 | Doxygen::functionNameSDict = new MemberNameSDict(10000); ␊ |
9281 | Doxygen::functionNameSDict->setAutoDelete(TRUE);␊ |
9282 | Doxygen::groupSDict = new GroupSDict(17); ␊ |
9283 | Doxygen::groupSDict->setAutoDelete(TRUE);␊ |
9284 | Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>");␊ |
9285 | Doxygen::namespaceSDict = new NamespaceSDict(20); ␊ |
9286 | Doxygen::namespaceSDict->setAutoDelete(TRUE);␊ |
9287 | Doxygen::classSDict = new ClassSDict(1009); ␊ |
9288 | Doxygen::classSDict->setAutoDelete(TRUE);␊ |
9289 | Doxygen::hiddenClasses = new ClassSDict(257);␊ |
9290 | Doxygen::hiddenClasses->setAutoDelete(TRUE);␊ |
9291 | Doxygen::directories = new DirSDict(17);␊ |
9292 | Doxygen::directories->setAutoDelete(TRUE);␊ |
9293 | Doxygen::pageSDict = new PageSDict(1009); // all doc pages␊ |
9294 | Doxygen::pageSDict->setAutoDelete(TRUE);␊ |
9295 | Doxygen::exampleSDict = new PageSDict(1009); // all examples␊ |
9296 | Doxygen::exampleSDict->setAutoDelete(TRUE);␊ |
9297 | Doxygen::inputNameDict = new FileNameDict(10007);␊ |
9298 | Doxygen::includeNameDict = new FileNameDict(10007);␊ |
9299 | Doxygen::exampleNameDict = new FileNameDict(1009);␊ |
9300 | Doxygen::exampleNameDict->setAutoDelete(TRUE);␊ |
9301 | Doxygen::imageNameDict = new FileNameDict(257);␊ |
9302 | Doxygen::dotFileNameDict = new FileNameDict(257);␊ |
9303 | Doxygen::mscFileNameDict = new FileNameDict(257);␊ |
9304 | Doxygen::sectionDict.setAutoDelete(TRUE);␊ |
9305 | Doxygen::memGrpInfoDict.setAutoDelete(TRUE);␊ |
9306 | Doxygen::tagDestinationDict.setAutoDelete(TRUE);␊ |
9307 | Doxygen::lookupCache.setAutoDelete(TRUE);␊ |
9308 | Doxygen::dirRelations.setAutoDelete(TRUE);␊ |
9309 | }␊ |
9310 | ␊ |
9311 | void cleanUpDoxygen()␊ |
9312 | {␊ |
9313 | delete Doxygen::inputNameDict;␊ |
9314 | delete Doxygen::includeNameDict;␊ |
9315 | delete Doxygen::exampleNameDict;␊ |
9316 | delete Doxygen::imageNameDict;␊ |
9317 | delete Doxygen::dotFileNameDict;␊ |
9318 | delete Doxygen::mscFileNameDict;␊ |
9319 | delete Doxygen::mainPage;␊ |
9320 | delete Doxygen::pageSDict; ␊ |
9321 | delete Doxygen::exampleSDict;␊ |
9322 | delete Doxygen::globalScope;␊ |
9323 | delete Doxygen::xrefLists;␊ |
9324 | delete Doxygen::parserManager;␊ |
9325 | cleanUpPreprocessor();␊ |
9326 | delete theTranslator;␊ |
9327 | delete g_outputList;␊ |
9328 | Mappers::freeMappers();␊ |
9329 | codeFreeScanner();␊ |
9330 | ␊ |
9331 | if (Doxygen::symbolMap)␊ |
9332 | {␊ |
9333 | // iterate through Doxygen::symbolMap and delete all␊ |
9334 | // DefinitionList objects, since they have no owner␊ |
9335 | QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);␊ |
9336 | DefinitionIntf *di;␊ |
9337 | for (dli.toFirst();(di=dli.current());)␊ |
9338 | {␊ |
9339 | if (di->definitionType()==DefinitionIntf::TypeSymbolList)␊ |
9340 | {␊ |
9341 | DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());␊ |
9342 | delete (DefinitionList *)tmp;␊ |
9343 | }␊ |
9344 | else␊ |
9345 | {␊ |
9346 | ++dli;␊ |
9347 | }␊ |
9348 | } ␊ |
9349 | }␊ |
9350 | ␊ |
9351 | delete Doxygen::inputNameList;␊ |
9352 | delete Doxygen::memberNameSDict;␊ |
9353 | delete Doxygen::functionNameSDict;␊ |
9354 | delete Doxygen::groupSDict;␊ |
9355 | delete Doxygen::classSDict;␊ |
9356 | delete Doxygen::hiddenClasses;␊ |
9357 | delete Doxygen::namespaceSDict;␊ |
9358 | delete Doxygen::directories;␊ |
9359 | ␊ |
9360 | //delete Doxygen::symbolMap; <- we cannot do this unless all static lists ␊ |
9361 | // (such as Doxygen::namespaceSDict)␊ |
9362 | // with objects based on Definition are made␊ |
9363 | // dynamic first␊ |
9364 | }␊ |
9365 | ␊ |
9366 | void readConfiguration(int argc, char **argv)␊ |
9367 | {␊ |
9368 | /**************************************************************************␊ |
9369 | * Handle arguments *␊ |
9370 | **************************************************************************/␊ |
9371 | ␊ |
9372 | int optind=1;␊ |
9373 | const char *configName=0;␊ |
9374 | const char *layoutName=0;␊ |
9375 | const char *debugLabel;␊ |
9376 | const char *formatName;␊ |
9377 | bool genConfig=FALSE;␊ |
9378 | bool shortList=FALSE;␊ |
9379 | bool updateConfig=FALSE;␊ |
9380 | bool genLayout=FALSE;␊ |
9381 | while (optind<argc && argv[optind][0]=='-' && ␊ |
9382 | (isalpha(argv[optind][1]) || argv[optind][1]=='?' || ␊ |
9383 | argv[optind][1]=='-')␊ |
9384 | )␊ |
9385 | {␊ |
9386 | switch(argv[optind][1])␊ |
9387 | {␊ |
9388 | case 'g':␊ |
9389 | genConfig=TRUE;␊ |
9390 | configName=getArg(argc,argv,optind);␊ |
9391 | if (strcmp(argv[optind+1],"-")==0)␊ |
9392 | { configName="-"; optind++; }␊ |
9393 | if (!configName) ␊ |
9394 | { configName="Doxyfile"; }␊ |
9395 | break;␊ |
9396 | case 'l':␊ |
9397 | genLayout=TRUE;␊ |
9398 | layoutName=getArg(argc,argv,optind);␊ |
9399 | if (!layoutName)␊ |
9400 | { layoutName="DoxygenLayout.xml"; }␊ |
9401 | break;␊ |
9402 | case 'd':␊ |
9403 | debugLabel=getArg(argc,argv,optind);␊ |
9404 | Debug::setFlag(debugLabel);␊ |
9405 | break;␊ |
9406 | case 's':␊ |
9407 | shortList=TRUE;␊ |
9408 | break;␊ |
9409 | case 'u':␊ |
9410 | updateConfig=TRUE;␊ |
9411 | break;␊ |
9412 | case 'e':␊ |
9413 | formatName=getArg(argc,argv,optind);␊ |
9414 | if (!formatName)␊ |
9415 | {␊ |
9416 | err("error: option -e is missing format specifier rtf.\n");␊ |
9417 | cleanUpDoxygen();␊ |
9418 | exit(1);␊ |
9419 | }␊ |
9420 | if (stricmp(formatName,"rtf")==0)␊ |
9421 | {␊ |
9422 | if (optind+1>=argc)␊ |
9423 | {␊ |
9424 | err("error: option \"-e rtf\" is missing an extensions file name\n");␊ |
9425 | cleanUpDoxygen();␊ |
9426 | exit(1);␊ |
9427 | }␊ |
9428 | QFile f;␊ |
9429 | if (openOutputFile(argv[optind+1],f))␊ |
9430 | {␊ |
9431 | RTFGenerator::writeExtensionsFile(f);␊ |
9432 | }␊ |
9433 | cleanUpDoxygen();␊ |
9434 | exit(1);␊ |
9435 | }␊ |
9436 | err("error: option \"-e\" has invalid format specifier.\n");␊ |
9437 | cleanUpDoxygen();␊ |
9438 | exit(1);␊ |
9439 | break; ␊ |
9440 | case 'w':␊ |
9441 | formatName=getArg(argc,argv,optind);␊ |
9442 | if (!formatName)␊ |
9443 | {␊ |
9444 | err("error: option -w is missing format specifier rtf, html or latex\n");␊ |
9445 | cleanUpDoxygen();␊ |
9446 | exit(1);␊ |
9447 | } ␊ |
9448 | if (stricmp(formatName,"rtf")==0)␊ |
9449 | {␊ |
9450 | if (optind+1>=argc)␊ |
9451 | {␊ |
9452 | err("error: option \"-w rtf\" is missing a style sheet file name\n");␊ |
9453 | cleanUpDoxygen();␊ |
9454 | exit(1);␊ |
9455 | }␊ |
9456 | QFile f;␊ |
9457 | if (openOutputFile(argv[optind+1],f))␊ |
9458 | {␊ |
9459 | RTFGenerator::writeStyleSheetFile(f);␊ |
9460 | }␊ |
9461 | cleanUpDoxygen();␊ |
9462 | exit(1);␊ |
9463 | }␊ |
9464 | else if (stricmp(formatName,"html")==0)␊ |
9465 | {␊ |
9466 | if (optind+4<argc || QFileInfo("Doxyfile").exists())␊ |
9467 | {␊ |
9468 | QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");␊ |
9469 | if (!Config::instance()->parse(df))␊ |
9470 | {␊ |
9471 | err("error opening or reading configuration file %s!\n",argv[optind+4]);␊ |
9472 | cleanUpDoxygen();␊ |
9473 | exit(1);␊ |
9474 | }␊ |
9475 | Config::instance()->substituteEnvironmentVars();␊ |
9476 | Config::instance()->convertStrToVal();␊ |
9477 | // avoid bootstrapping issues when the config file already␊ |
9478 | // refers to the files that we are supposed to parse.␊ |
9479 | Config_getString("HTML_HEADER")="";␊ |
9480 | Config_getString("HTML_FOOTER")="";␊ |
9481 | Config::instance()->check();␊ |
9482 | }␊ |
9483 | else␊ |
9484 | {␊ |
9485 | Config::instance()->init();␊ |
9486 | }␊ |
9487 | if (optind+3>=argc)␊ |
9488 | {␊ |
9489 | err("error: option \"-w html\" does not have enough arguments\n");␊ |
9490 | cleanUpDoxygen();␊ |
9491 | exit(1);␊ |
9492 | }␊ |
9493 | ␊ |
9494 | QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");␊ |
9495 | if (!setTranslator(outputLanguage))␊ |
9496 | {␊ |
9497 | err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());␊ |
9498 | }␊ |
9499 | ␊ |
9500 | QFile f;␊ |
9501 | if (openOutputFile(argv[optind+1],f))␊ |
9502 | {␊ |
9503 | HtmlGenerator::writeHeaderFile(f, argv[optind+3]);␊ |
9504 | }␊ |
9505 | f.close();␊ |
9506 | if (openOutputFile(argv[optind+2],f))␊ |
9507 | {␊ |
9508 | HtmlGenerator::writeFooterFile(f);␊ |
9509 | }␊ |
9510 | f.close();␊ |
9511 | if (openOutputFile(argv[optind+3],f))␊ |
9512 | {␊ |
9513 | HtmlGenerator::writeStyleSheetFile(f);␊ |
9514 | } ␊ |
9515 | cleanUpDoxygen();␊ |
9516 | exit(0);␊ |
9517 | }␊ |
9518 | else if (stricmp(formatName,"latex")==0)␊ |
9519 | {␊ |
9520 | if (optind+4<argc) // use config file to get settings␊ |
9521 | {␊ |
9522 | if (!Config::instance()->parse(argv[optind+4]))␊ |
9523 | {␊ |
9524 | err("error opening or reading configuration file %s!\n",argv[optind+4]);␊ |
9525 | exit(1);␊ |
9526 | }␊ |
9527 | Config::instance()->substituteEnvironmentVars();␊ |
9528 | Config::instance()->convertStrToVal();␊ |
9529 | Config_getString("LATEX_HEADER")="";␊ |
9530 | Config::instance()->check();␊ |
9531 | }␊ |
9532 | else // use default config␊ |
9533 | {␊ |
9534 | Config::instance()->init();␊ |
9535 | }␊ |
9536 | if (optind+3>=argc)␊ |
9537 | {␊ |
9538 | err("error: option \"-w latex\" does not have enough arguments\n");␊ |
9539 | cleanUpDoxygen();␊ |
9540 | exit(1);␊ |
9541 | }␊ |
9542 | ␊ |
9543 | QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");␊ |
9544 | if (!setTranslator(outputLanguage))␊ |
9545 | {␊ |
9546 | err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());␊ |
9547 | }␊ |
9548 | ␊ |
9549 | QFile f;␊ |
9550 | if (openOutputFile(argv[optind+1],f))␊ |
9551 | {␊ |
9552 | LatexGenerator::writeHeaderFile(f);␊ |
9553 | }␊ |
9554 | f.close();␊ |
9555 | if (openOutputFile(argv[optind+2],f))␊ |
9556 | {␊ |
9557 | LatexGenerator::writeFooterFile(f);␊ |
9558 | }␊ |
9559 | f.close();␊ |
9560 | if (openOutputFile(argv[optind+3],f))␊ |
9561 | {␊ |
9562 | LatexGenerator::writeStyleSheetFile(f);␊ |
9563 | }␊ |
9564 | cleanUpDoxygen();␊ |
9565 | exit(0);␊ |
9566 | }␊ |
9567 | else ␊ |
9568 | {␊ |
9569 | err("error: Illegal format specifier %s: should be one of rtf, html, or latex\n",formatName);␊ |
9570 | cleanUpDoxygen();␊ |
9571 | exit(1);␊ |
9572 | }␊ |
9573 | break;␊ |
9574 | case 'm':␊ |
9575 | g_dumpSymbolMap = TRUE;␊ |
9576 | break;␊ |
9577 | case 'x':␊ |
9578 | g_dumpConfigAsXML = TRUE;␊ |
9579 | break;␊ |
9580 | case '-':␊ |
9581 | if (strcmp(&argv[optind][2],"help")==0)␊ |
9582 | {␊ |
9583 | usage(argv[0]);␊ |
9584 | }␊ |
9585 | else if (strcmp(&argv[optind][2],"version")==0)␊ |
9586 | {␊ |
9587 | msg("%s\n",versionString); ␊ |
9588 | cleanUpDoxygen();␊ |
9589 | exit(0);␊ |
9590 | }␊ |
9591 | break;␊ |
9592 | case 'b':␊ |
9593 | setvbuf(stdout,NULL,_IONBF,0);␊ |
9594 | Doxygen::outputToWizard=TRUE;␊ |
9595 | break;␊ |
9596 | case 'h':␊ |
9597 | case '?':␊ |
9598 | usage(argv[0]);␊ |
9599 | break;␊ |
9600 | default:␊ |
9601 | err("Unknown option -%c\n",argv[optind][1]);␊ |
9602 | usage(argv[0]);␊ |
9603 | }␊ |
9604 | optind++;␊ |
9605 | }␊ |
9606 | ␊ |
9607 | /**************************************************************************␊ |
9608 | * Parse or generate the config file *␊ |
9609 | **************************************************************************/␊ |
9610 | ␊ |
9611 | Config::instance()->init();␊ |
9612 | ␊ |
9613 | if (genConfig)␊ |
9614 | {␊ |
9615 | if (g_dumpConfigAsXML)␊ |
9616 | {␊ |
9617 | checkConfiguration();␊ |
9618 | generateConfigFile(configName,shortList);␊ |
9619 | dumpConfigAsXML();␊ |
9620 | exit(0); ␊ |
9621 | }␊ |
9622 | else␊ |
9623 | {␊ |
9624 | generateConfigFile(configName,shortList);␊ |
9625 | }␊ |
9626 | cleanUpDoxygen();␊ |
9627 | exit(0);␊ |
9628 | }␊ |
9629 | if (genLayout)␊ |
9630 | {␊ |
9631 | writeDefaultLayoutFile(layoutName);␊ |
9632 | cleanUpDoxygen();␊ |
9633 | exit(0);␊ |
9634 | }␊ |
9635 | ␊ |
9636 | QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");␊ |
9637 | if (optind>=argc)␊ |
9638 | { ␊ |
9639 | if (configFileInfo1.exists()) ␊ |
9640 | {␊ |
9641 | configName="Doxyfile";␊ |
9642 | }␊ |
9643 | else if (configFileInfo2.exists())␊ |
9644 | {␊ |
9645 | configName="doxyfile";␊ |
9646 | }␊ |
9647 | else␊ |
9648 | {␊ |
9649 | err("Doxyfile not found and no input file specified!\n");␊ |
9650 | usage(argv[0]);␊ |
9651 | }␊ |
9652 | }␊ |
9653 | else␊ |
9654 | {␊ |
9655 | QFileInfo fi(argv[optind]);␊ |
9656 | if (fi.exists() || strcmp(argv[optind],"-")==0)␊ |
9657 | {␊ |
9658 | configName=argv[optind];␊ |
9659 | }␊ |
9660 | else␊ |
9661 | {␊ |
9662 | err("error: configuration file %s not found!\n",argv[optind]);␊ |
9663 | usage(argv[0]);␊ |
9664 | }␊ |
9665 | }␊ |
9666 | ␊ |
9667 | ␊ |
9668 | if (!Config::instance()->parse(configName))␊ |
9669 | {␊ |
9670 | err("error: could not open or read configuration file %s!\n",configName);␊ |
9671 | cleanUpDoxygen();␊ |
9672 | exit(1);␊ |
9673 | }␊ |
9674 | ␊ |
9675 | if (updateConfig)␊ |
9676 | {␊ |
9677 | generateConfigFile(configName,shortList,TRUE);␊ |
9678 | cleanUpDoxygen();␊ |
9679 | exit(0);␊ |
9680 | }␊ |
9681 | ␊ |
9682 | /* Perlmod wants to know the path to the config file.*/␊ |
9683 | QFileInfo configFileInfo(configName);␊ |
9684 | setPerlModDoxyfile(configFileInfo.absFilePath().data());␊ |
9685 | ␊ |
9686 | }␊ |
9687 | ␊ |
9688 | /** check and resolve config options */␊ |
9689 | void checkConfiguration()␊ |
9690 | {␊ |
9691 | ␊ |
9692 | Config::instance()->substituteEnvironmentVars();␊ |
9693 | Config::instance()->convertStrToVal();␊ |
9694 | Config::instance()->check();␊ |
9695 | ␊ |
9696 | initWarningFormat();␊ |
9697 | }␊ |
9698 | ␊ |
9699 | /** adjust globals that depend on configuration settings. */␊ |
9700 | void adjustConfiguration()␊ |
9701 | {␊ |
9702 | QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");␊ |
9703 | if (!setTranslator(outputLanguage))␊ |
9704 | {␊ |
9705 | err("warning: Output language %s not supported! Using English instead.\n",␊ |
9706 | outputLanguage.data());␊ |
9707 | }␊ |
9708 | QStrList &includePath = Config_getList("INCLUDE_PATH");␊ |
9709 | char *s=includePath.first();␊ |
9710 | while (s)␊ |
9711 | {␊ |
9712 | QFileInfo fi(s);␊ |
9713 | addSearchDir(fi.absFilePath());␊ |
9714 | s=includePath.next();␊ |
9715 | }␊ |
9716 | ␊ |
9717 | /* Set the global html file extension. */ ␊ |
9718 | Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");␊ |
9719 | ␊ |
9720 | ␊ |
9721 | Doxygen::xrefLists->setAutoDelete(TRUE);␊ |
9722 | ␊ |
9723 | Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") || ␊ |
9724 | Config_getBool("CALLER_GRAPH") ||␊ |
9725 | Config_getBool("REFERENCES_RELATION") ||␊ |
9726 | Config_getBool("REFERENCED_BY_RELATION");␊ |
9727 | ␊ |
9728 | /**************************************************************************␊ |
9729 | * Add custom extension mappings␊ |
9730 | **************************************************************************/␊ |
9731 | ␊ |
9732 | QStrList &extMaps = Config_getList("EXTENSION_MAPPING");␊ |
9733 | char *mapping = extMaps.first();␊ |
9734 | while (mapping)␊ |
9735 | {␊ |
9736 | QCString mapStr = mapping;␊ |
9737 | int i;␊ |
9738 | if ((i=mapStr.find('='))!=-1)␊ |
9739 | {␊ |
9740 | QCString ext=mapStr.left(i).stripWhiteSpace().lower();␊ |
9741 | QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();␊ |
9742 | if (!updateLanguageMapping(ext,language))␊ |
9743 | {␊ |
9744 | err("Failed to map file extension '%s' to unsupported language '%s'.\n"␊ |
9745 | "Check the EXTENSION_MAPPING setting in the config file.\n", ␊ |
9746 | ext.data(),language.data());␊ |
9747 | }␊ |
9748 | else␊ |
9749 | {␊ |
9750 | msg("Adding custom extension mapping: .%s will be treated as language %s\n",␊ |
9751 | ext.data(),language.data());␊ |
9752 | }␊ |
9753 | }␊ |
9754 | mapping = extMaps.next();␊ |
9755 | }␊ |
9756 | ␊ |
9757 | ␊ |
9758 | // add predefined macro name to a dictionary␊ |
9759 | QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");␊ |
9760 | s=expandAsDefinedList.first();␊ |
9761 | while (s)␊ |
9762 | {␊ |
9763 | if (Doxygen::expandAsDefinedDict[s]==0)␊ |
9764 | {␊ |
9765 | Doxygen::expandAsDefinedDict.insert(s,(void *)666);␊ |
9766 | }␊ |
9767 | s=expandAsDefinedList.next();␊ |
9768 | }␊ |
9769 | ␊ |
9770 | // read aliases and store them in a dictionary␊ |
9771 | readAliases();␊ |
9772 | ␊ |
9773 | // store number of spaces in a tab into Doxygen::spaces␊ |
9774 | int &tabSize = Config_getInt("TAB_SIZE");␊ |
9775 | Doxygen::spaces.resize(tabSize+1);␊ |
9776 | int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';␊ |
9777 | Doxygen::spaces.at(tabSize)='\0';␊ |
9778 | }␊ |
9779 | ␊ |
9780 | #ifdef HAS_SIGNALS␊ |
9781 | static void stopDoxygen(int)␊ |
9782 | {␊ |
9783 | QDir thisDir;␊ |
9784 | msg("Cleaning up...\n");␊ |
9785 | if (!Doxygen::entryDBFileName.isEmpty())␊ |
9786 | {␊ |
9787 | thisDir.remove(Doxygen::entryDBFileName);␊ |
9788 | }␊ |
9789 | if (!Doxygen::objDBFileName.isEmpty())␊ |
9790 | {␊ |
9791 | thisDir.remove(Doxygen::objDBFileName);␊ |
9792 | }␊ |
9793 | exit(1);␊ |
9794 | }␊ |
9795 | #endif␊ |
9796 | ␊ |
9797 | static void exitDoxygen()␊ |
9798 | {␊ |
9799 | if (!g_successfulRun) // premature exit␊ |
9800 | {␊ |
9801 | QDir thisDir;␊ |
9802 | msg("Exiting...\n");␊ |
9803 | if (!Doxygen::entryDBFileName.isEmpty())␊ |
9804 | {␊ |
9805 | thisDir.remove(Doxygen::entryDBFileName);␊ |
9806 | }␊ |
9807 | if (!Doxygen::objDBFileName.isEmpty())␊ |
9808 | {␊ |
9809 | thisDir.remove(Doxygen::objDBFileName);␊ |
9810 | }␊ |
9811 | }␊ |
9812 | }␊ |
9813 | ␊ |
9814 | static QCString createOutputDirectory(const QCString &baseDirName,␊ |
9815 | const char *formatDirOption,␊ |
9816 | const char *defaultDirName)␊ |
9817 | {␊ |
9818 | // Note the & on the next line, we modify the formatDirOption!␊ |
9819 | QCString &formatDirName = Config_getString(formatDirOption);␊ |
9820 | if (formatDirName.isEmpty())␊ |
9821 | {␊ |
9822 | formatDirName = baseDirName + defaultDirName;␊ |
9823 | }␊ |
9824 | else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))␊ |
9825 | {␊ |
9826 | formatDirName.prepend(baseDirName+'/');␊ |
9827 | }␊ |
9828 | QDir formatDir(formatDirName);␊ |
9829 | if (!formatDir.exists() && !formatDir.mkdir(formatDirName))␊ |
9830 | {␊ |
9831 | err("Could not create output directory %s\n", formatDirName.data());␊ |
9832 | cleanUpDoxygen();␊ |
9833 | exit(1);␊ |
9834 | }␊ |
9835 | return formatDirName;␊ |
9836 | }␊ |
9837 | ␊ |
9838 | static QCString getQchFileName()␊ |
9839 | {␊ |
9840 | QCString const & qchFile = Config_getString("QCH_FILE");␊ |
9841 | if (!qchFile.isEmpty())␊ |
9842 | {␊ |
9843 | return qchFile;␊ |
9844 | }␊ |
9845 | ␊ |
9846 | QCString const & projectName = Config_getString("PROJECT_NAME");␊ |
9847 | QCString const & versionText = Config_getString("PROJECT_NUMBER");␊ |
9848 | ␊ |
9849 | return QCString("../qch/")␊ |
9850 | + (projectName.isEmpty() ? QCString("index") : projectName)␊ |
9851 | + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)␊ |
9852 | + QCString(".qch");␊ |
9853 | }␊ |
9854 | ␊ |
9855 | void searchInputFiles(StringList &inputFiles)␊ |
9856 | {␊ |
9857 | QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");␊ |
9858 | bool alwaysRecursive = Config_getBool("RECURSIVE");␊ |
9859 | StringDict excludeNameDict(1009);␊ |
9860 | excludeNameDict.setAutoDelete(TRUE);␊ |
9861 | ␊ |
9862 | // gather names of all files in the include path␊ |
9863 | msg("Searching for include files...\n");␊ |
9864 | QStrList &includePathList = Config_getList("INCLUDE_PATH");␊ |
9865 | char *s=includePathList.first();␊ |
9866 | while (s)␊ |
9867 | {␊ |
9868 | QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");␊ |
9869 | if (pl.count()==0) ␊ |
9870 | {␊ |
9871 | pl = Config_getList("FILE_PATTERNS");␊ |
9872 | }␊ |
9873 | readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,␊ |
9874 | &exclPatterns,0,0,␊ |
9875 | alwaysRecursive);␊ |
9876 | s=includePathList.next(); ␊ |
9877 | }␊ |
9878 | ␊ |
9879 | msg("Searching for example files...\n");␊ |
9880 | QStrList &examplePathList = Config_getList("EXAMPLE_PATH");␊ |
9881 | s=examplePathList.first();␊ |
9882 | while (s)␊ |
9883 | {␊ |
9884 | readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,␊ |
9885 | &Config_getList("EXAMPLE_PATTERNS"),␊ |
9886 | 0,0,0,␊ |
9887 | (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));␊ |
9888 | s=examplePathList.next(); ␊ |
9889 | }␊ |
9890 | ␊ |
9891 | msg("Searching for images...\n");␊ |
9892 | QStrList &imagePathList=Config_getList("IMAGE_PATH");␊ |
9893 | s=imagePathList.first();␊ |
9894 | while (s)␊ |
9895 | {␊ |
9896 | readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,␊ |
9897 | 0,0,0,␊ |
9898 | alwaysRecursive);␊ |
9899 | s=imagePathList.next(); ␊ |
9900 | }␊ |
9901 | ␊ |
9902 | msg("Searching for dot files...\n");␊ |
9903 | QStrList &dotFileList=Config_getList("DOTFILE_DIRS");␊ |
9904 | s=dotFileList.first();␊ |
9905 | while (s)␊ |
9906 | {␊ |
9907 | readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,␊ |
9908 | 0,0,0,␊ |
9909 | alwaysRecursive);␊ |
9910 | s=dotFileList.next(); ␊ |
9911 | }␊ |
9912 | ␊ |
9913 | msg("Searching for msc files...\n");␊ |
9914 | QStrList &mscFileList=Config_getList("MSCFILE_DIRS");␊ |
9915 | s=mscFileList.first();␊ |
9916 | while (s)␊ |
9917 | {␊ |
9918 | readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,␊ |
9919 | 0,0,0,␊ |
9920 | alwaysRecursive);␊ |
9921 | s=dotFileList.next(); ␊ |
9922 | }␊ |
9923 | ␊ |
9924 | ␊ |
9925 | msg("Searching for files to exclude\n");␊ |
9926 | QStrList &excludeList = Config_getList("EXCLUDE");␊ |
9927 | s=excludeList.first();␊ |
9928 | while (s)␊ |
9929 | {␊ |
9930 | readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),␊ |
9931 | 0,0,&excludeNameDict,␊ |
9932 | alwaysRecursive,␊ |
9933 | FALSE);␊ |
9934 | s=excludeList.next();␊ |
9935 | }␊ |
9936 | ␊ |
9937 | /**************************************************************************␊ |
9938 | * Determine Input Files *␊ |
9939 | **************************************************************************/␊ |
9940 | ␊ |
9941 | msg("Searching for files to process...\n");␊ |
9942 | QDict<void> *killDict = new QDict<void>(10007);␊ |
9943 | int inputSize=0;␊ |
9944 | QStrList &inputList=Config_getList("INPUT");␊ |
9945 | inputFiles.setAutoDelete(TRUE);␊ |
9946 | s=inputList.first();␊ |
9947 | while (s)␊ |
9948 | {␊ |
9949 | QCString path=s;␊ |
9950 | uint l = path.length();␊ |
9951 | // strip trailing slashes␊ |
9952 | if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);␊ |
9953 | ␊ |
9954 | inputSize+=readFileOrDirectory(␊ |
9955 | path,␊ |
9956 | Doxygen::inputNameList,␊ |
9957 | Doxygen::inputNameDict,␊ |
9958 | &excludeNameDict,␊ |
9959 | &Config_getList("FILE_PATTERNS"),␊ |
9960 | &exclPatterns,␊ |
9961 | &inputFiles,0,␊ |
9962 | alwaysRecursive,␊ |
9963 | TRUE,␊ |
9964 | killDict);␊ |
9965 | s=inputList.next();␊ |
9966 | }␊ |
9967 | delete killDict;␊ |
9968 | }␊ |
9969 | ␊ |
9970 | ␊ |
9971 | void parseInput()␊ |
9972 | {␊ |
9973 | atexit(exitDoxygen);␊ |
9974 | ␊ |
9975 | ␊ |
9976 | /**************************************************************************␊ |
9977 | * Make sure the output directory exists␊ |
9978 | **************************************************************************/␊ |
9979 | QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");␊ |
9980 | if (outputDirectory.isEmpty()) ␊ |
9981 | {␊ |
9982 | outputDirectory=QDir::currentDirPath();␊ |
9983 | }␊ |
9984 | else␊ |
9985 | {␊ |
9986 | QDir dir(outputDirectory);␊ |
9987 | if (!dir.exists())␊ |
9988 | {␊ |
9989 | dir.setPath(QDir::currentDirPath());␊ |
9990 | if (!dir.mkdir(outputDirectory))␊ |
9991 | {␊ |
9992 | err("error: tag OUTPUT_DIRECTORY: Output directory `%s' does not "␊ |
9993 | ␉ "exist and cannot be created\n",outputDirectory.data());␊ |
9994 | cleanUpDoxygen();␊ |
9995 | exit(1);␊ |
9996 | }␊ |
9997 | else if (!Config_getBool("QUIET"))␊ |
9998 | {␊ |
9999 | ␉err("Notice: Output directory `%s' does not exist. "␊ |
10000 | ␉ "I have created it for you.\n", outputDirectory.data());␊ |
10001 | }␊ |
10002 | dir.cd(outputDirectory);␊ |
10003 | }␊ |
10004 | outputDirectory=dir.absPath();␊ |
10005 | }␊ |
10006 | ␊ |
10007 | /**************************************************************************␊ |
10008 | * Initialize global lists and dictionaries␊ |
10009 | **************************************************************************/␊ |
10010 | ␊ |
10011 | int cacheSize = Config_getInt("SYMBOL_CACHE_SIZE");␊ |
10012 | if (cacheSize<0) cacheSize=0;␊ |
10013 | if (cacheSize>9) cacheSize=9;␊ |
10014 | Doxygen::symbolCache = new ObjCache(16+cacheSize); // 16 -> room for 65536 elements, ␊ |
10015 | // ~2.0 MByte "overhead"␊ |
10016 | Doxygen::symbolStorage = new Store;␊ |
10017 | ␊ |
10018 | #ifdef HAS_SIGNALS␊ |
10019 | signal(SIGINT, stopDoxygen);␊ |
10020 | #endif␊ |
10021 | ␊ |
10022 | uint pid = portable_pid();␊ |
10023 | Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);␊ |
10024 | Doxygen::objDBFileName.prepend(outputDirectory+"/");␊ |
10025 | Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);␊ |
10026 | Doxygen::entryDBFileName.prepend(outputDirectory+"/");␊ |
10027 | ␊ |
10028 | if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)␊ |
10029 | {␊ |
10030 | err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());␊ |
10031 | exit(1);␊ |
10032 | }␊ |
10033 | ␊ |
10034 | ␊ |
10035 | /**************************************************************************␊ |
10036 | * Initialize some global constants␊ |
10037 | **************************************************************************/␊ |
10038 | ␊ |
10039 | g_compoundKeywordDict.insert("template class",(void *)8);␊ |
10040 | g_compoundKeywordDict.insert("template struct",(void *)8);␊ |
10041 | g_compoundKeywordDict.insert("class",(void *)8);␊ |
10042 | g_compoundKeywordDict.insert("struct",(void *)8);␊ |
10043 | g_compoundKeywordDict.insert("union",(void *)8);␊ |
10044 | g_compoundKeywordDict.insert("interface",(void *)8);␊ |
10045 | g_compoundKeywordDict.insert("exception",(void *)8);␊ |
10046 | ␊ |
10047 | ␊ |
10048 | /**************************************************************************␊ |
10049 | * Check/create output directorties *␊ |
10050 | **************************************************************************/␊ |
10051 | ␊ |
10052 | QCString htmlOutput;␊ |
10053 | bool &generateHtml = Config_getBool("GENERATE_HTML");␊ |
10054 | if (generateHtml)␊ |
10055 | htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");␊ |
10056 | ␊ |
10057 | QCString xmlOutput;␊ |
10058 | bool &generateXml = Config_getBool("GENERATE_XML");␊ |
10059 | if (generateXml)␊ |
10060 | xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");␊ |
10061 | ␊ |
10062 | QCString latexOutput;␊ |
10063 | bool &generateLatex = Config_getBool("GENERATE_LATEX");␊ |
10064 | if (generateLatex)␊ |
10065 | latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");␊ |
10066 | ␊ |
10067 | QCString rtfOutput;␊ |
10068 | bool &generateRtf = Config_getBool("GENERATE_RTF");␊ |
10069 | if (generateRtf)␊ |
10070 | rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");␊ |
10071 | ␊ |
10072 | QCString manOutput;␊ |
10073 | bool &generateMan = Config_getBool("GENERATE_MAN");␊ |
10074 | if (generateMan)␊ |
10075 | manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");␊ |
10076 | ␊ |
10077 | ␊ |
10078 | if (Config_getBool("HAVE_DOT"))␊ |
10079 | {␊ |
10080 | QCString curFontPath = Config_getString("DOT_FONTPATH");␊ |
10081 | if (curFontPath.isEmpty())␊ |
10082 | {␊ |
10083 | portable_getenv("DOTFONTPATH");␊ |
10084 | QCString newFontPath = ".";␊ |
10085 | if (!curFontPath.isEmpty())␊ |
10086 | {␊ |
10087 | newFontPath+=portable_pathListSeparator();␊ |
10088 | newFontPath+=curFontPath;␊ |
10089 | }␊ |
10090 | portable_setenv("DOTFONTPATH",newFontPath);␊ |
10091 | }␊ |
10092 | else␊ |
10093 | {␊ |
10094 | portable_setenv("DOTFONTPATH",curFontPath);␊ |
10095 | }␊ |
10096 | }␊ |
10097 | ␊ |
10098 | ␊ |
10099 | ␊ |
10100 | /**************************************************************************␊ |
10101 | * Handle layout file *␊ |
10102 | **************************************************************************/␊ |
10103 | ␊ |
10104 | LayoutDocManager::instance().init();␊ |
10105 | QCString layoutFileName = Config_getString("LAYOUT_FILE");␊ |
10106 | bool defaultLayoutUsed = FALSE;␊ |
10107 | if (layoutFileName.isEmpty())␊ |
10108 | {␊ |
10109 | layoutFileName = "DoxygenLayout.xml";␊ |
10110 | defaultLayoutUsed = TRUE;␊ |
10111 | }␊ |
10112 | ␊ |
10113 | QFile layoutFile(layoutFileName);␊ |
10114 | if (layoutFile.open(IO_ReadOnly))␊ |
10115 | {␊ |
10116 | msg("Parsing layout file %s...\n",layoutFileName.data());␊ |
10117 | QTextStream t(&layoutFile); ␊ |
10118 | t.setEncoding(QTextStream::Latin1);␊ |
10119 | LayoutDocManager::instance().parse(t);␊ |
10120 | }␊ |
10121 | else if (!defaultLayoutUsed)␊ |
10122 | {␊ |
10123 | err("warning: failed to open layout file '%s' for reading!\n",layoutFileName.data());␊ |
10124 | }␊ |
10125 | ␊ |
10126 | /**************************************************************************␊ |
10127 | * Read and preprocess input *␊ |
10128 | **************************************************************************/␊ |
10129 | ␊ |
10130 | // prevent search in the output directories␊ |
10131 | QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");␊ |
10132 | if (generateHtml) exclPatterns.append(htmlOutput);␊ |
10133 | if (generateXml) exclPatterns.append(xmlOutput);␊ |
10134 | if (generateLatex) exclPatterns.append(latexOutput);␊ |
10135 | if (generateRtf) exclPatterns.append(rtfOutput);␊ |
10136 | if (generateMan) exclPatterns.append(manOutput);␊ |
10137 | ␊ |
10138 | ␊ |
10139 | searchInputFiles(g_inputFiles);␊ |
10140 | ␊ |
10141 | // Notice: the order of the function calls below is very important!␊ |
10142 | ␊ |
10143 | if (Config_getBool("GENERATE_HTML"))␊ |
10144 | {␊ |
10145 | readFormulaRepository();␊ |
10146 | }␊ |
10147 | ␊ |
10148 | /**************************************************************************␊ |
10149 | * Handle Tag Files *␊ |
10150 | **************************************************************************/␊ |
10151 | ␊ |
10152 | g_storage = new FileStorage;␊ |
10153 | g_storage->setName(Doxygen::entryDBFileName);␊ |
10154 | if (!g_storage->open(IO_WriteOnly))␊ |
10155 | {␊ |
10156 | err("Failed to create temporary storage file %s\n",␊ |
10157 | Doxygen::entryDBFileName.data());␊ |
10158 | exit(1);␊ |
10159 | }␊ |
10160 | Entry *root=new Entry;␊ |
10161 | EntryNav *rootNav = new EntryNav(0,root);␊ |
10162 | rootNav->setEntry(root);␊ |
10163 | msg("Reading and parsing tag files\n");␊ |
10164 | ␊ |
10165 | QStrList &tagFileList = Config_getList("TAGFILES");␊ |
10166 | char *s=tagFileList.first();␊ |
10167 | while (s)␊ |
10168 | {␊ |
10169 | readTagFile(root,s);␊ |
10170 | root->createNavigationIndex(rootNav,g_storage,0);␊ |
10171 | s=tagFileList.next();␊ |
10172 | }␊ |
10173 | ␊ |
10174 | /**************************************************************************␊ |
10175 | * Parse source files * ␊ |
10176 | **************************************************************************/␊ |
10177 | ␊ |
10178 | parseFiles(root,rootNav);␊ |
10179 | g_storage->close();␊ |
10180 | if (!g_storage->open(IO_ReadOnly))␊ |
10181 | {␊ |
10182 | err("Failed to open temporary storage file %s for reading",␊ |
10183 | Doxygen::entryDBFileName.data());␊ |
10184 | exit(1);␊ |
10185 | }␊ |
10186 | ␊ |
10187 | //printNavTree(rootNav,0);␊ |
10188 | ␊ |
10189 | // we are done with input scanning now, so free up the buffers used by flex␊ |
10190 | // (can be around 4MB)␊ |
10191 | preFreeScanner();␊ |
10192 | scanFreeScanner();␊ |
10193 | pyscanFreeScanner();␊ |
10194 | ␊ |
10195 | //delete rootNav;␊ |
10196 | //g_storage.close();␊ |
10197 | //exit(1);␊ |
10198 | ␊ |
10199 | /**************************************************************************␊ |
10200 | * Gather information * ␊ |
10201 | **************************************************************************/␊ |
10202 | ␊ |
10203 | msg("Building group list...\n");␊ |
10204 | buildGroupList(rootNav);␊ |
10205 | organizeSubGroups(rootNav);␊ |
10206 | ␊ |
10207 | msg("Building directory list...\n");␊ |
10208 | buildDirectories();␊ |
10209 | findDirDocumentation(rootNav);␊ |
10210 | ␊ |
10211 | if (Config_getBool("BUILTIN_STL_SUPPORT"))␊ |
10212 | {␊ |
10213 | addSTLClasses(rootNav);␊ |
10214 | }␊ |
10215 | ␊ |
10216 | msg("Building namespace list...\n");␊ |
10217 | buildNamespaceList(rootNav);␊ |
10218 | findUsingDirectives(rootNav);␊ |
10219 | ␊ |
10220 | msg("Building file list...\n");␊ |
10221 | buildFileList(rootNav);␊ |
10222 | //generateFileTree();␊ |
10223 | ␊ |
10224 | msg("Building class list...\n");␊ |
10225 | buildClassList(rootNav);␊ |
10226 | ␊ |
10227 | msg("Associating documentation with classes...\n");␊ |
10228 | buildClassDocList(rootNav);␊ |
10229 | ␊ |
10230 | // build list of using declarations here (global list)␊ |
10231 | buildListOfUsingDecls(rootNav);␊ |
10232 | ␊ |
10233 | msg("Computing nesting relations for classes...\n");␊ |
10234 | resolveClassNestingRelations();␊ |
10235 | distributeClassGroupRelations();␊ |
10236 | ␊ |
10237 | // calling buildClassList may result in cached relations that␊ |
10238 | // become invalid after resolveClassNestingRelations(), that's why␊ |
10239 | // we need to clear the cache here␊ |
10240 | Doxygen::lookupCache.clear();␊ |
10241 | // we don't need the list of using declaration anymore␊ |
10242 | g_usingDeclarations.clear();␊ |
10243 | ␊ |
10244 | msg("Building example list...\n");␊ |
10245 | buildExampleList(rootNav);␊ |
10246 | ␊ |
10247 | msg("Searching for enumerations...\n");␊ |
10248 | findEnums(rootNav);␊ |
10249 | ␊ |
10250 | // Since buildVarList calls isVarWithConstructor␊ |
10251 | // and this calls getResolvedClass we need to process␊ |
10252 | // typedefs first so the relations between classes via typedefs␊ |
10253 | // are properly resolved. See bug 536385 for an example.␊ |
10254 | msg("Searching for documented typedefs...\n");␊ |
10255 | buildTypedefList(rootNav);␊ |
10256 | ␊ |
10257 | msg("Searching for members imported via using declarations...\n");␊ |
10258 | findUsingDeclImports(rootNav);␊ |
10259 | // this should be after buildTypedefList in order to properly import␊ |
10260 | // used typedefs␊ |
10261 | findUsingDeclarations(rootNav);␊ |
10262 | ␊ |
10263 | msg("Searching for included using directives...\n");␊ |
10264 | findIncludedUsingDirectives();␊ |
10265 | ␊ |
10266 | msg("Searching for documented variables...\n");␊ |
10267 | buildVarList(rootNav);␊ |
10268 | ␊ |
10269 | msg("Building member list...\n"); // using class info only !␊ |
10270 | buildFunctionList(rootNav);␊ |
10271 | ␊ |
10272 | msg("Searching for friends...\n");␊ |
10273 | findFriends();␊ |
10274 | ␊ |
10275 | msg("Searching for documented defines...\n");␊ |
10276 | findDefineDocumentation(rootNav); ␊ |
10277 | ␊ |
10278 | findClassEntries(rootNav); ␊ |
10279 | msg("Computing class inheritance relations...\n");␊ |
10280 | findInheritedTemplateInstances(); ␊ |
10281 | msg("Computing class usage relations...\n");␊ |
10282 | findUsedTemplateInstances(); ␊ |
10283 | ␊ |
10284 | msg("Flushing cached template relations that have become invalid...\n");␊ |
10285 | flushCachedTemplateRelations();␊ |
10286 | ␊ |
10287 | msg("Creating members for template instances...\n");␊ |
10288 | createTemplateInstanceMembers();␊ |
10289 | ␊ |
10290 | msg("Computing class relations...\n");␊ |
10291 | computeTemplateClassRelations(); ␊ |
10292 | flushUnresolvedRelations();␊ |
10293 | ␊ |
10294 | computeClassRelations(); ␊ |
10295 | ␊ |
10296 | if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))␊ |
10297 | VhdlDocGen::computeVhdlComponentRelations();␊ |
10298 | ␊ |
10299 | g_classEntries.clear(); ␊ |
10300 | ␊ |
10301 | msg("Add enum values to enums...\n");␊ |
10302 | addEnumValuesToEnums(rootNav);␊ |
10303 | findEnumDocumentation(rootNav);␊ |
10304 | ␊ |
10305 | msg("Searching for member function documentation...\n");␊ |
10306 | findObjCMethodDefinitions(rootNav);␊ |
10307 | findMemberDocumentation(rootNav); // may introduce new members !␊ |
10308 | ␊ |
10309 | transferRelatedFunctionDocumentation();␊ |
10310 | transferFunctionDocumentation();␊ |
10311 | ␊ |
10312 | msg("Building page list...\n");␊ |
10313 | buildPageList(rootNav);␊ |
10314 | ␊ |
10315 | msg("Search for main page...\n");␊ |
10316 | findMainPage(rootNav);␊ |
10317 | ␊ |
10318 | msg("Computing page relations...\n");␊ |
10319 | computePageRelations(rootNav);␊ |
10320 | checkPageRelations();␊ |
10321 | ␊ |
10322 | msg("Determining the scope of groups...\n");␊ |
10323 | findGroupScope(rootNav);␊ |
10324 | ␊ |
10325 | msg("Sorting lists...\n");␊ |
10326 | Doxygen::memberNameSDict->sort();␊ |
10327 | Doxygen::functionNameSDict->sort();␊ |
10328 | Doxygen::hiddenClasses->sort();␊ |
10329 | Doxygen::classSDict->sort();␊ |
10330 | ␊ |
10331 | msg("Freeing entry tree\n");␊ |
10332 | delete rootNav;␊ |
10333 | g_storage->close();␊ |
10334 | delete g_storage;␊ |
10335 | g_storage=0;␊ |
10336 | ␊ |
10337 | QDir thisDir;␊ |
10338 | thisDir.remove(Doxygen::entryDBFileName);␊ |
10339 | ␊ |
10340 | msg("Determining which enums are documented\n");␊ |
10341 | findDocumentedEnumValues();␊ |
10342 | ␊ |
10343 | msg("Computing member relations...\n");␊ |
10344 | computeMemberRelations();␊ |
10345 | ␊ |
10346 | msg("Building full member lists recursively...\n");␊ |
10347 | buildCompleteMemberLists();␊ |
10348 | ␊ |
10349 | msg("Adding members to member groups.\n");␊ |
10350 | addMembersToMemberGroup();␊ |
10351 | ␊ |
10352 | if (Config_getBool("DISTRIBUTE_GROUP_DOC"))␊ |
10353 | {␊ |
10354 | msg("Distributing member group documentation.\n");␊ |
10355 | distributeMemberGroupDocumentation();␊ |
10356 | }␊ |
10357 | ␊ |
10358 | msg("Computing member references...\n");␊ |
10359 | computeMemberReferences(); ␊ |
10360 | ␊ |
10361 | if (Config_getBool("INHERIT_DOCS"))␊ |
10362 | {␊ |
10363 | msg("Inheriting documentation...\n");␊ |
10364 | inheritDocumentation();␊ |
10365 | }␊ |
10366 | ␊ |
10367 | // compute the shortest possible names of all files␊ |
10368 | // without loosing the uniqueness of the file names.␊ |
10369 | msg("Generating disk names...\n");␊ |
10370 | Doxygen::inputNameList->generateDiskNames();␊ |
10371 | ␊ |
10372 | msg("Adding source references...\n");␊ |
10373 | addSourceReferences();␊ |
10374 | ␊ |
10375 | msg("Adding xrefitems...\n");␊ |
10376 | addListReferences();␊ |
10377 | generateXRefPages();␊ |
10378 | ␊ |
10379 | msg("Sorting member lists...\n");␊ |
10380 | sortMemberLists();␊ |
10381 | ␊ |
10382 | if (Config_getBool("SHOW_DIRECTORIES") && Config_getBool("DIRECTORY_GRAPH"))␊ |
10383 | {␊ |
10384 | msg("Computing dependencies between directories...\n");␊ |
10385 | computeDirDependencies();␊ |
10386 | }␊ |
10387 | ␊ |
10388 | msg("Counting data structures...\n");␊ |
10389 | countDataStructures();␊ |
10390 | ␊ |
10391 | msg("Resolving user defined references...\n");␊ |
10392 | resolveUserReferences();␊ |
10393 | ␊ |
10394 | msg("Finding anchors and sections in the documentation...\n");␊ |
10395 | findSectionsInDocumentation();␊ |
10396 | ␊ |
10397 | transferFunctionReferences();␊ |
10398 | ␊ |
10399 | msg("Combining using relations...\n");␊ |
10400 | combineUsingRelations();␊ |
10401 | ␊ |
10402 | msg("Adding members to index pages...\n");␊ |
10403 | addMembersToIndex();␊ |
10404 | }␊ |
10405 | ␊ |
10406 | void generateOutput()␊ |
10407 | {␊ |
10408 | /**************************************************************************␊ |
10409 | * Initialize output generators *␊ |
10410 | **************************************************************************/␊ |
10411 | ␊ |
10412 | //// dump all symbols␊ |
10413 | //SDict<DefinitionList>::Iterator sdi(Doxygen::symbolMap);␊ |
10414 | //DefinitionList *dl;␊ |
10415 | //for (sdi.toFirst();(dl=sdi.current());++sdi)␊ |
10416 | //{␊ |
10417 | // DefinitionListIterator dli(*dl);␊ |
10418 | // Definition *d;␊ |
10419 | // printf("Symbol: ");␊ |
10420 | // for (dli.toFirst();(d=dli.current());++dli)␊ |
10421 | // {␊ |
10422 | // printf("%s ",d->qualifiedName().data());␊ |
10423 | // }␊ |
10424 | // printf("\n");␊ |
10425 | //}␊ |
10426 | if (g_dumpSymbolMap)␊ |
10427 | {␊ |
10428 | dumpSymbolMap();␊ |
10429 | exit(0);␊ |
10430 | }␊ |
10431 | ␊ |
10432 | initDocParser();␊ |
10433 | ␊ |
10434 | g_outputList = new OutputList(TRUE);␊ |
10435 | if (Config_getBool("GENERATE_HTML")) ␊ |
10436 | {␊ |
10437 | g_outputList->add(new HtmlGenerator);␊ |
10438 | HtmlGenerator::init();␊ |
10439 | ␊ |
10440 | bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP");␊ |
10441 | bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");␊ |
10442 | bool generateQhp = Config_getBool("GENERATE_QHP");␊ |
10443 | bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");␊ |
10444 | bool generateDocSet = Config_getBool("GENERATE_DOCSET");␊ |
10445 | if (generateEclipseHelp) Doxygen::indexList.addIndex(new EclipseHelp);␊ |
10446 | if (generateHtmlHelp) Doxygen::indexList.addIndex(new HtmlHelp);␊ |
10447 | if (generateQhp) Doxygen::indexList.addIndex(new Qhp);␊ |
10448 | if (generateTreeView) Doxygen::indexList.addIndex(new FTVHelp(TRUE));␊ |
10449 | if (generateDocSet) Doxygen::indexList.addIndex(new DocSets);␊ |
10450 | Doxygen::indexList.initialize();␊ |
10451 | HtmlGenerator::writeTabData();␊ |
10452 | ␊ |
10453 | #if 0␊ |
10454 | if (Config_getBool("GENERATE_INDEXLOG")) Doxygen::indexList.addIndex(new IndexLog);␊ |
10455 | #endif␊ |
10456 | //if (Config_getBool("HTML_DYNAMIC_SECTIONS")) HtmlGenerator::generateSectionImages();␊ |
10457 | copyStyleSheet();␊ |
10458 | copyLogo();␊ |
10459 | copyExtraFiles();␊ |
10460 | if (!generateTreeView && Config_getBool("USE_INLINE_TREES"))␊ |
10461 | {␊ |
10462 | FTVHelp::generateTreeViewImages();␊ |
10463 | }␊ |
10464 | }␊ |
10465 | if (Config_getBool("GENERATE_LATEX")) ␊ |
10466 | {␊ |
10467 | g_outputList->add(new LatexGenerator);␊ |
10468 | LatexGenerator::init();␊ |
10469 | }␊ |
10470 | if (Config_getBool("GENERATE_MAN"))␊ |
10471 | {␊ |
10472 | g_outputList->add(new ManGenerator);␊ |
10473 | ManGenerator::init();␊ |
10474 | }␊ |
10475 | if (Config_getBool("GENERATE_RTF"))␊ |
10476 | {␊ |
10477 | g_outputList->add(new RTFGenerator);␊ |
10478 | RTFGenerator::init();␊ |
10479 | }␊ |
10480 | ␊ |
10481 | if (Config_getBool("USE_HTAGS"))␊ |
10482 | {␊ |
10483 | Htags::useHtags = TRUE;␊ |
10484 | QCString htmldir = Config_getString("HTML_OUTPUT");␊ |
10485 | if (!Htags::execute(htmldir))␊ |
10486 | err("error: USE_HTAGS is YES but htags(1) failed. \n");␊ |
10487 | if (!Htags::loadFilemap(htmldir))␊ |
10488 | err("error: htags(1) ended normally but failed to load the filemap. \n");␊ |
10489 | }␊ |
10490 | ␊ |
10491 | /**************************************************************************␊ |
10492 | * Generate documentation *␊ |
10493 | **************************************************************************/␊ |
10494 | ␊ |
10495 | QFile *tag=0;␊ |
10496 | QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");␊ |
10497 | if (!generateTagFile.isEmpty())␊ |
10498 | {␊ |
10499 | tag=new QFile(generateTagFile);␊ |
10500 | if (!tag->open(IO_WriteOnly))␊ |
10501 | {␊ |
10502 | err("error: cannot open tag file %s for writing\n",␊ |
10503 | generateTagFile.data()␊ |
10504 | );␊ |
10505 | cleanUpDoxygen();␊ |
10506 | exit(1);␊ |
10507 | }␊ |
10508 | Doxygen::tagFile.setDevice(tag);␊ |
10509 | Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?>" << endl;␊ |
10510 | Doxygen::tagFile << "<tagfile>" << endl;␊ |
10511 | }␊ |
10512 | ␊ |
10513 | if (Config_getBool("GENERATE_HTML")) writeDoxFont(Config_getString("HTML_OUTPUT"));␊ |
10514 | if (Config_getBool("GENERATE_LATEX")) writeDoxFont(Config_getString("LATEX_OUTPUT"));␊ |
10515 | if (Config_getBool("GENERATE_RTF")) writeDoxFont(Config_getString("RTF_OUTPUT"));␊ |
10516 | ␊ |
10517 | msg("Generating style sheet...\n");␊ |
10518 | //printf("writing style info\n");␊ |
10519 | QCString genString = ␊ |
10520 | theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME"));␊ |
10521 | g_outputList->writeStyleInfo(0); // write first part␊ |
10522 | g_outputList->disableAllBut(OutputGenerator::Latex);␊ |
10523 | g_outputList->parseText(genString);␊ |
10524 | g_outputList->writeStyleInfo(1); // write second part␊ |
10525 | //parseText(*g_outputList,theTranslator->trWrittenBy());␊ |
10526 | g_outputList->writeStyleInfo(2); // write third part␊ |
10527 | g_outputList->parseText(genString);␊ |
10528 | g_outputList->writeStyleInfo(3); // write fourth part␊ |
10529 | //parseText(*g_outputList,theTranslator->trWrittenBy());␊ |
10530 | g_outputList->writeStyleInfo(4); // write last part␊ |
10531 | g_outputList->enableAll();␊ |
10532 | ␊ |
10533 | static bool searchEngine = Config_getBool("SEARCHENGINE");␊ |
10534 | static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");␊ |
10535 | ␊ |
10536 | // generate search indices (need to do this before writing other HTML␊ |
10537 | // pages as these contain a drop down menu with options depending on␊ |
10538 | // what categories we find in this function.␊ |
10539 | if (Config_getBool("GENERATE_HTML") && searchEngine)␊ |
10540 | {␊ |
10541 | msg("Generating search indices...\n");␊ |
10542 | QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";␊ |
10543 | QDir searchDir(searchDirName);␊ |
10544 | if (!searchDir.exists() && !searchDir.mkdir(searchDirName))␊ |
10545 | {␊ |
10546 | err("error: Could not create search results directory '%s' $PWD='%s'\n",␊ |
10547 | searchDirName.data(),QDir::currentDirPath().data());␊ |
10548 | exit(1);␊ |
10549 | }␊ |
10550 | HtmlGenerator::writeSearchData(searchDirName);␊ |
10551 | if (!serverBasedSearch) // client side search index␊ |
10552 | {␊ |
10553 | writeJavascriptSearchIndex();␊ |
10554 | }␊ |
10555 | }␊ |
10556 | ␊ |
10557 | //statistics();␊ |
10558 | ␊ |
10559 | // count the number of documented elements in the lists we have built. ␊ |
10560 | // If the result is 0 we do not generate the lists and omit the ␊ |
10561 | // corresponding links in the index.␊ |
10562 | msg("Generating index page...\n"); ␊ |
10563 | writeIndex(*g_outputList);␊ |
10564 | ␊ |
10565 | msg("Generating page index...\n");␊ |
10566 | writePageIndex(*g_outputList);␊ |
10567 | ␊ |
10568 | msg("Generating example documentation...\n");␊ |
10569 | generateExampleDocs();␊ |
10570 | ␊ |
10571 | msg("Generating file sources...\n");␊ |
10572 | if (!Htags::useHtags)␊ |
10573 | {␊ |
10574 | generateFileSources();␊ |
10575 | }␊ |
10576 | ␊ |
10577 | msg("Generating file documentation...\n");␊ |
10578 | generateFileDocs();␊ |
10579 | ␊ |
10580 | msg("Generating page documentation...\n");␊ |
10581 | generatePageDocs();␊ |
10582 | ␊ |
10583 | msg("Generating group documentation...\n");␊ |
10584 | generateGroupDocs();␊ |
10585 | ␊ |
10586 | msg("Generating group index...\n");␊ |
10587 | writeGroupIndex(*g_outputList);␊ |
10588 | ␊ |
10589 | msg("Generating class documentation...\n");␊ |
10590 | generateClassDocs();␊ |
10591 | ␊ |
10592 | if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY"))␊ |
10593 | {␊ |
10594 | msg("Generating graphical class hierarchy...\n");␊ |
10595 | writeGraphicalClassHierarchy(*g_outputList);␊ |
10596 | }␊ |
10597 | ␊ |
10598 | msg("Generating namespace index...\n");␊ |
10599 | generateNamespaceDocs();␊ |
10600 | ␊ |
10601 | msg("Generating namespace member index...\n");␊ |
10602 | writeNamespaceMemberIndex(*g_outputList);␊ |
10603 | ␊ |
10604 | if (Config_getBool("GENERATE_LEGEND"))␊ |
10605 | {␊ |
10606 | msg("Generating graph info page...\n");␊ |
10607 | writeGraphInfo(*g_outputList);␊ |
10608 | }␊ |
10609 | ␊ |
10610 | if (Config_getBool("SHOW_DIRECTORIES"))␊ |
10611 | {␊ |
10612 | msg("Generating directory documentation...\n");␊ |
10613 | generateDirDocs(*g_outputList);␊ |
10614 | }␊ |
10615 | ␊ |
10616 | msg("Generating file index...\n");␊ |
10617 | writeFileIndex(*g_outputList);␊ |
10618 | ␊ |
10619 | if (Config_getBool("SHOW_DIRECTORIES"))␊ |
10620 | {␊ |
10621 | msg("Generating directory index...\n");␊ |
10622 | writeDirIndex(*g_outputList);␊ |
10623 | }␊ |
10624 | ␊ |
10625 | msg("Generating example index...\n");␊ |
10626 | writeExampleIndex(*g_outputList);␊ |
10627 | ␊ |
10628 | msg("Generating file member index...\n");␊ |
10629 | writeFileMemberIndex(*g_outputList);␊ |
10630 | ␊ |
10631 | ␊ |
10632 | //writeDirDependencyGraph(Config_getString("HTML_OUTPUT"));␊ |
10633 | ␊ |
10634 | if (Doxygen::formulaList.count()>0 && Config_getBool("GENERATE_HTML")␊ |
10635 | && !Config_getBool("USE_MATHJAX"))␊ |
10636 | {␊ |
10637 | msg("Generating bitmaps for formulas in HTML...\n");␊ |
10638 | Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT"));␊ |
10639 | }␊ |
10640 | ␊ |
10641 | //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_HTMLHELP")) ␊ |
10642 | //{␊ |
10643 | // HtmlHelp::getInstance()->finalize();␊ |
10644 | //}␊ |
10645 | //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_TREEVIEW")) ␊ |
10646 | //{␊ |
10647 | // FTVHelp::getInstance()->finalize();␊ |
10648 | //}␊ |
10649 | ␊ |
10650 | msg("finalizing index lists...\n");␊ |
10651 | Doxygen::indexList.finalize();␊ |
10652 | ␊ |
10653 | if (!Config_getString("GENERATE_TAGFILE").isEmpty())␊ |
10654 | {␊ |
10655 | Doxygen::tagFile << "</tagfile>" << endl;␊ |
10656 | delete tag;␊ |
10657 | }␊ |
10658 | ␊ |
10659 | if (Config_getBool("DOT_CLEANUP"))␊ |
10660 | {␊ |
10661 | if (Config_getBool("GENERATE_HTML"))␊ |
10662 | removeDoxFont(Config_getString("HTML_OUTPUT"));␊ |
10663 | if (Config_getBool("GENERATE_RTF")) ␊ |
10664 | removeDoxFont(Config_getString("RTF_OUTPUT"));␊ |
10665 | if (Config_getBool("GENERATE_LATEX")) ␊ |
10666 | removeDoxFont(Config_getString("LATEX_OUTPUT"));␊ |
10667 | }␊ |
10668 | ␊ |
10669 | if (Config_getBool("GENERATE_XML"))␊ |
10670 | {␊ |
10671 | msg("Generating XML output...\n");␊ |
10672 | generateXML();␊ |
10673 | }␊ |
10674 | if (Config_getBool("GENERATE_AUTOGEN_DEF"))␊ |
10675 | {␊ |
10676 | msg("Generating AutoGen DEF output...\n");␊ |
10677 | generateDEF();␊ |
10678 | }␊ |
10679 | if (Config_getBool("GENERATE_PERLMOD"))␊ |
10680 | {␊ |
10681 | msg("Generating Perl module output...\n");␊ |
10682 | generatePerlMod();␊ |
10683 | }␊ |
10684 | if (Config_getBool("GENERATE_HTML") && searchEngine && serverBasedSearch)␊ |
10685 | {␊ |
10686 | msg("Generating search index\n");␊ |
10687 | HtmlGenerator::writeSearchPage();␊ |
10688 | Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");␊ |
10689 | }␊ |
10690 | ␊ |
10691 | if (Config_getBool("GENERATE_RTF"))␊ |
10692 | {␊ |
10693 | msg("Combining RTF output...\n");␊ |
10694 | if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))␊ |
10695 | {␊ |
10696 | err("An error occurred during post-processing the RTF files!\n");␊ |
10697 | }␊ |
10698 | }␊ |
10699 | ␊ |
10700 | if (Config_getBool("HAVE_DOT"))␊ |
10701 | {␊ |
10702 | DotManager::instance()->run();␊ |
10703 | }␊ |
10704 | ␊ |
10705 | if (Config_getBool("GENERATE_HTML") &&␊ |
10706 | Config_getBool("GENERATE_HTMLHELP") && ␊ |
10707 | !Config_getString("HHC_LOCATION").isEmpty())␊ |
10708 | {␊ |
10709 | msg("Running html help compiler...\n");␊ |
10710 | QString oldDir = QDir::currentDirPath();␊ |
10711 | QDir::setCurrent(Config_getString("HTML_OUTPUT"));␊ |
10712 | portable_sysTimerStart();␊ |
10713 | if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))␊ |
10714 | {␊ |
10715 | err("error: failed to run html help compiler on index.hhp\n");␊ |
10716 | }␊ |
10717 | portable_sysTimerStop();␊ |
10718 | QDir::setCurrent(oldDir);␊ |
10719 | }␊ |
10720 | if ( Config_getBool("GENERATE_HTML") &&␊ |
10721 | Config_getBool("GENERATE_QHP") && ␊ |
10722 | !Config_getString("QHG_LOCATION").isEmpty())␊ |
10723 | {␊ |
10724 | msg("Running qhelpgenerator...\n");␊ |
10725 | QCString const qhpFileName = Qhp::getQhpFileName();␊ |
10726 | QCString const qchFileName = getQchFileName();␊ |
10727 | ␊ |
10728 | QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());␊ |
10729 | QString const oldDir = QDir::currentDirPath();␊ |
10730 | QDir::setCurrent(Config_getString("HTML_OUTPUT"));␊ |
10731 | portable_sysTimerStart();␊ |
10732 | if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))␊ |
10733 | {␊ |
10734 | err("error: failed to run qhelpgenerator on index.qhp\n");␊ |
10735 | }␊ |
10736 | portable_sysTimerStop();␊ |
10737 | QDir::setCurrent(oldDir);␊ |
10738 | }␊ |
10739 | ␊ |
10740 | ␊ |
10741 | if (Debug::isFlagSet(Debug::Time))␊ |
10742 | {␊ |
10743 | msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",␊ |
10744 | ((double)Doxygen::runningTime.elapsed())/1000.0,␊ |
10745 | portable_getSysElapsedTime()␊ |
10746 | );␊ |
10747 | }␊ |
10748 | else␊ |
10749 | {␊ |
10750 | msg("finished...\n");␊ |
10751 | }␊ |
10752 | ␊ |
10753 | /**************************************************************************␊ |
10754 | * Start cleaning up *␊ |
10755 | **************************************************************************/␊ |
10756 | ␊ |
10757 | //Doxygen::symbolCache->printStats();␊ |
10758 | //Doxygen::symbolStorage->printStats();␊ |
10759 | cleanUpDoxygen();␊ |
10760 | ␊ |
10761 | finializeDocParser();␊ |
10762 | Doxygen::symbolStorage->close();␊ |
10763 | QDir thisDir;␊ |
10764 | thisDir.remove(Doxygen::objDBFileName);␊ |
10765 | Config::deleteInstance();␊ |
10766 | QTextCodec::deleteAllCodecs();␊ |
10767 | delete Doxygen::symbolCache;␊ |
10768 | delete Doxygen::symbolMap;␊ |
10769 | delete Doxygen::symbolStorage;␊ |
10770 | g_successfulRun=TRUE;␊ |
10771 | }␊ |
10772 | ␊ |
10773 |