]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: xmlparser.h | |
3 | // Purpose: Parser of the API/interface XML files | |
4 | // Author: Francesco Montorsi | |
5 | // Created: 2008/03/17 | |
6 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) 2008 Francesco Montorsi | |
8 | // Licence: wxWindows licence | |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | ||
12 | #ifndef _XMLPARSER_H_ | |
13 | #define _XMLPARSER_H_ | |
14 | ||
15 | #include <wx/txtstrm.h> | |
16 | #include <wx/dynarray.h> | |
17 | #include <wx/xml/xml.h> | |
18 | #include <wx/platinfo.h> | |
19 | #include <wx/log.h> | |
20 | ||
21 | ||
22 | /* | |
23 | IMPORTANT | |
24 | ========= | |
25 | ||
26 | Any fix aimed to reduce "false positives" which involves | |
27 | references to a specific wxWidgets class is marked in | |
28 | ifacecheck sources with the string: | |
29 | ||
30 | // ADHOC-FIX: | |
31 | // ...fix description... | |
32 | */ | |
33 | ||
34 | // NOTE: all messages in this way are printed on the stderr | |
35 | //#define wxLogWarning wxLogMessage | |
36 | ||
37 | ||
38 | // ---------------------------------------------------------------------------- | |
39 | // Represents a type with or without const/static/ qualifier | |
40 | // and with or without & and * operators | |
41 | // ---------------------------------------------------------------------------- | |
42 | class wxType | |
43 | { | |
44 | public: | |
45 | wxType() {} | |
46 | wxType(const wxString& type) | |
47 | { SetTypeFromString(type); } | |
48 | ||
49 | void SetTypeFromString(const wxString& t); | |
50 | wxString GetAsString() const | |
51 | { return m_strType; } | |
52 | ||
53 | // returns this type _without_ any decoration, | |
54 | // including the & (which indicates this is a reference), | |
55 | // the * (which indicates this is a pointer), etc. | |
56 | wxString GetAsCleanString() const | |
57 | { return m_strTypeClean; } | |
58 | ||
59 | bool IsConst() const | |
60 | { return m_strType.Contains("const"); } | |
61 | bool IsStatic() const | |
62 | { return m_strType.Contains("static"); } | |
63 | bool IsPointer() const | |
64 | { return m_strType.Contains("*"); } | |
65 | bool IsReference() const | |
66 | { return m_strType.Contains("&"); } | |
67 | ||
68 | bool operator==(const wxType& m) const; | |
69 | bool operator!=(const wxType& m) const | |
70 | { return !(*this == m); } | |
71 | ||
72 | bool IsOk() const; | |
73 | ||
74 | protected: | |
75 | wxString m_strType, | |
76 | m_strTypeClean; // m_strType "cleaned" of its attributes | |
77 | // (only for internal use) | |
78 | }; | |
79 | ||
80 | extern wxType wxEmptyType; | |
81 | WX_DECLARE_OBJARRAY(wxType, wxTypeArray); | |
82 | ||
83 | ||
84 | // ---------------------------------------------------------------------------- | |
85 | // Represents a type used as argument for some wxMethod | |
86 | // ---------------------------------------------------------------------------- | |
87 | class wxArgumentType : public wxType | |
88 | { | |
89 | public: | |
90 | wxArgumentType() {} | |
91 | wxArgumentType(const wxString& type, const wxString& defVal, | |
92 | const wxString& argName = wxEmptyString) | |
93 | { SetTypeFromString(type); SetDefaultValue(defVal); m_strArgName = argName; } | |
94 | ||
95 | void SetArgumentName(const wxString& name) | |
96 | { m_strArgName=name.Strip(wxString::both); } | |
97 | wxString GetArgumentName() const | |
98 | { return m_strArgName; } | |
99 | ||
100 | void SetDefaultValue(const wxString& defval, | |
101 | const wxString& defvalForCmp = wxEmptyString); | |
102 | wxString GetDefaultValue() const | |
103 | { return m_strDefaultValue; } | |
104 | ||
105 | // returns the default value used for comparisons | |
106 | wxString GetDefaultCleanValue() const | |
107 | { return m_strDefaultValueForCmp; } | |
108 | ||
109 | bool HasDefaultValue() const | |
110 | { return !m_strDefaultValue.IsEmpty(); } | |
111 | ||
112 | bool operator==(const wxArgumentType& m) const; | |
113 | bool operator!=(const wxArgumentType& m) const | |
114 | { return !(*this == m); } | |
115 | ||
116 | protected: | |
117 | wxString m_strDefaultValue; | |
118 | ||
119 | // this string may differ from m_strDefaultValue if there were | |
120 | // preprocessor substitutions or other "replacements" done to | |
121 | // avoid false errors. | |
122 | wxString m_strDefaultValueForCmp; | |
123 | ||
124 | // the argument name | |
125 | wxString m_strArgName; | |
126 | }; | |
127 | ||
128 | extern wxArgumentType wxEmptyArgumentType; | |
129 | WX_DECLARE_OBJARRAY(wxArgumentType, wxArgumentTypeArray); | |
130 | ||
131 | ||
132 | enum wxMethodAccessSpecifier | |
133 | { | |
134 | wxMAS_PUBLIC, | |
135 | wxMAS_PROTECTED, | |
136 | wxMAS_PRIVATE | |
137 | }; | |
138 | ||
139 | // ---------------------------------------------------------------------------- | |
140 | // Represents a single prototype of a class' member. | |
141 | // ---------------------------------------------------------------------------- | |
142 | class wxMethod | |
143 | { | |
144 | public: | |
145 | wxMethod() | |
146 | { m_bConst=m_bVirtual=m_bPureVirtual=m_bStatic=m_bDeprecated=false; | |
147 | m_nLine=-1; m_nAvailability=wxPORT_UNKNOWN; m_access=wxMAS_PUBLIC; } | |
148 | ||
149 | wxMethod(const wxType& rettype, const wxString& name, | |
150 | const wxArgumentTypeArray& arguments, | |
151 | bool isConst, bool isStatic, bool isVirtual) | |
152 | : m_retType(rettype), m_strName(name.Strip(wxString::both)), | |
153 | m_bConst(isConst), m_bStatic(isStatic), m_bVirtual(isVirtual) | |
154 | { SetArgumentTypes(arguments); m_nLine=-1; } | |
155 | ||
156 | ||
157 | public: // getters | |
158 | ||
159 | // bWithArgumentNames = output argument names? | |
160 | // bCleanDefaultValues = output clean argument default values? | |
161 | // bDeprecated = output [deprecated] next to deprecated methods? | |
162 | // bAccessSpec = output [public], [protected] or [private] next to method? | |
163 | // | |
164 | // TODO: convert to readable flags this set of bools | |
165 | wxString GetAsString(bool bWithArgumentNames = true, | |
166 | bool bCleanDefaultValues = false, | |
167 | bool bDeprecated = false, | |
168 | bool bAccessSpec = false) const; | |
169 | ||
170 | // parser of the prototype: | |
171 | // all these functions return strings with spaces stripped | |
172 | wxType GetReturnType() const | |
173 | { return m_retType; } | |
174 | wxString GetName() const | |
175 | { return m_strName; } | |
176 | const wxArgumentTypeArray& GetArgumentTypes() const | |
177 | { return m_args; } | |
178 | wxArgumentTypeArray& GetArgumentTypes() | |
179 | { return m_args; } | |
180 | int GetLocation() const | |
181 | { return m_nLine; } | |
182 | int GetAvailability() const | |
183 | { return m_nAvailability; } | |
184 | wxMethodAccessSpecifier GetAccessSpecifier() const | |
185 | { return m_access; } | |
186 | ||
187 | bool IsConst() const | |
188 | { return m_bConst; } | |
189 | bool IsStatic() const | |
190 | { return m_bStatic; } | |
191 | bool IsVirtual() const | |
192 | { return m_bVirtual; } | |
193 | bool IsPureVirtual() const | |
194 | { return m_bPureVirtual; } | |
195 | ||
196 | bool IsOk() const; | |
197 | bool IsCtor() const | |
198 | { return m_retType==wxEmptyType && !m_strName.StartsWith("~"); } | |
199 | bool IsDtor() const | |
200 | { return m_retType==wxEmptyType && m_strName.StartsWith("~"); } | |
201 | bool IsOperator() const | |
202 | { return m_strName.StartsWith("operator"); } | |
203 | ||
204 | bool IsDeprecated() const | |
205 | { return m_bDeprecated; } | |
206 | ||
207 | ||
208 | ||
209 | public: // setters | |
210 | ||
211 | void SetReturnType(const wxType& t) | |
212 | { m_retType=t; } | |
213 | void SetName(const wxString& name) | |
214 | { m_strName=name; } | |
215 | void SetArgumentTypes(const wxArgumentTypeArray& arr) | |
216 | { m_args=arr; } | |
217 | void SetConst(bool c = true) | |
218 | { m_bConst=c; } | |
219 | void SetStatic(bool c = true) | |
220 | { m_bStatic=c; } | |
221 | void SetVirtual(bool c = true) | |
222 | { m_bVirtual=c; } | |
223 | void SetPureVirtual(bool c = true) | |
224 | { | |
225 | m_bPureVirtual=c; | |
226 | if (c) m_bVirtual=c; // pure virtual => virtual | |
227 | } | |
228 | void SetDeprecated(bool c = true) | |
229 | { m_bDeprecated=c; } | |
230 | void SetLocation(int lineNumber) | |
231 | { m_nLine=lineNumber; } | |
232 | void SetAvailability(int nAvail) | |
233 | { m_nAvailability=nAvail; } | |
234 | void SetAccessSpecifier(wxMethodAccessSpecifier spec) | |
235 | { m_access=spec; } | |
236 | ||
237 | public: // misc | |
238 | ||
239 | bool operator==(const wxMethod&) const; | |
240 | bool operator!=(const wxMethod& m) const | |
241 | { return !(*this == m); } | |
242 | ||
243 | // this function works like operator== but tests everything: | |
244 | // - method name | |
245 | // - return type | |
246 | // - argument types | |
247 | // except for the method attributes (const,static,virtual,pureVirtual,deprecated) | |
248 | bool MatchesExceptForAttributes(const wxMethod& m) const; | |
249 | ||
250 | // returns true if this is a ctor which has default values for all its | |
251 | // argument, thus is able to act also as default ctor | |
252 | bool ActsAsDefaultCtor() const; | |
253 | ||
254 | // dumps the contents of this class in the given stream | |
255 | void Dump(wxTextOutputStream& stream) const; | |
256 | ||
257 | protected: | |
258 | wxType m_retType; | |
259 | wxString m_strName; | |
260 | wxArgumentTypeArray m_args; | |
261 | ||
262 | // misc attributes: | |
263 | bool m_bConst; | |
264 | bool m_bStatic; | |
265 | bool m_bVirtual; | |
266 | bool m_bPureVirtual; | |
267 | bool m_bDeprecated; | |
268 | ||
269 | // m_nLine can be -1 if no location infos are available | |
270 | int m_nLine; | |
271 | ||
272 | // this is a combination of wxPORT_* flags (see wxPortId) or wxPORT_UNKNOWN | |
273 | // if this method should be available for all wxWidgets ports. | |
274 | // NOTE: this is not used for comparing wxMethod objects | |
275 | // (gccXML never gives this kind of info). | |
276 | int m_nAvailability; | |
277 | ||
278 | // the access specifier for this method | |
279 | wxMethodAccessSpecifier m_access; | |
280 | }; | |
281 | ||
282 | WX_DECLARE_OBJARRAY(wxMethod, wxMethodArray); | |
283 | WX_DEFINE_ARRAY(const wxMethod*, wxMethodPtrArray); | |
284 | ||
285 | ||
286 | // we need wxClassPtrArray to be defined _before_ wxClass itself, | |
287 | // since wxClass uses wxClassPtrArray. | |
288 | class wxClass; | |
289 | WX_DEFINE_ARRAY(const wxClass*, wxClassPtrArray); | |
290 | ||
291 | class wxXmlInterface; | |
292 | ||
293 | ||
294 | // ---------------------------------------------------------------------------- | |
295 | // Represents a class of the wx API/interface. | |
296 | // ---------------------------------------------------------------------------- | |
297 | class wxClass | |
298 | { | |
299 | public: | |
300 | wxClass() {} | |
301 | wxClass(const wxString& name, const wxString& headername) | |
302 | : m_strName(name), m_strHeader(headername) {} | |
303 | ||
304 | ||
305 | public: // setters | |
306 | ||
307 | void SetHeader(const wxString& header) | |
308 | { m_strHeader=header; } | |
309 | void SetName(const wxString& name) | |
310 | { m_strName=name; } | |
311 | void SetAvailability(int nAvail) | |
312 | { m_nAvailability=nAvail; } | |
313 | void SetParent(unsigned int k, const wxString& name) | |
314 | { m_parents[k]=name; } | |
315 | ||
316 | public: // getters | |
317 | ||
318 | bool IsOk() const | |
319 | { return !m_strName.IsEmpty() && !m_methods.IsEmpty(); } | |
320 | ||
321 | bool IsValidCtorForThisClass(const wxMethod& m) const; | |
322 | bool IsValidDtorForThisClass(const wxMethod& m) const; | |
323 | ||
324 | wxString GetName() const | |
325 | { return m_strName; } | |
326 | wxString GetHeader() const | |
327 | { return m_strHeader; } | |
328 | wxString GetNameWithoutTemplate() const; | |
329 | ||
330 | unsigned int GetMethodCount() const | |
331 | { return m_methods.GetCount(); } | |
332 | wxMethod& GetMethod(unsigned int n) const | |
333 | { return m_methods[n]; } | |
334 | wxMethod& GetLastMethod() const | |
335 | { return m_methods.Last(); } | |
336 | ||
337 | int GetAvailability() const | |
338 | { return m_nAvailability; } | |
339 | ||
340 | //const wxClass *GetParent(unsigned int i) const | |
341 | const wxString& GetParent(unsigned int i) const | |
342 | { return m_parents[i]; } | |
343 | unsigned int GetParentCount() const | |
344 | { return m_parents.GetCount(); } | |
345 | ||
346 | public: // misc | |
347 | ||
348 | void AddMethod(const wxMethod& func) | |
349 | { m_methods.Add(func); } | |
350 | ||
351 | void AddParent(const wxString& parent)//wxClass* parent) | |
352 | { m_parents.Add(parent); } | |
353 | ||
354 | // returns a single result (the first, which is also the only | |
355 | // one if CheckConsistency() return true) | |
356 | const wxMethod* FindMethod(const wxMethod& m) const; | |
357 | ||
358 | // like FindMethod() but this one searches also recursively in | |
359 | // the parents of this class. | |
360 | const wxMethod* RecursiveUpwardFindMethod(const wxMethod& m, | |
361 | const wxXmlInterface* allclasses) const; | |
362 | ||
363 | // returns an array of pointers to the overloaded methods with the | |
364 | // same given name | |
365 | wxMethodPtrArray FindMethodsNamed(const wxString& name) const; | |
366 | ||
367 | // like FindMethodsNamed() but this one searches also recursively in | |
368 | // the parents of this class. | |
369 | wxMethodPtrArray RecursiveUpwardFindMethodsNamed(const wxString& name, | |
370 | const wxXmlInterface* allclasses) const; | |
371 | ||
372 | // dumps all methods to the given output stream | |
373 | void Dump(wxTextOutputStream& stream) const; | |
374 | ||
375 | // slow check | |
376 | bool CheckConsistency() const; | |
377 | ||
378 | protected: | |
379 | wxString m_strName; | |
380 | wxString m_strHeader; | |
381 | wxMethodArray m_methods; | |
382 | ||
383 | // name of the base classes: we store the names and not the pointers | |
384 | // because this makes _much_ easier the parsing process! | |
385 | // (basically because when parsing class X which derives from Y, | |
386 | // we may have not parsed yet class Y!) | |
387 | wxArrayString m_parents; | |
388 | ||
389 | // see the wxMethod::m_nAvailability field for more info | |
390 | int m_nAvailability; | |
391 | }; | |
392 | ||
393 | WX_DECLARE_OBJARRAY(wxClass, wxClassArray); | |
394 | ||
395 | ||
396 | ||
397 | // ---------------------------------------------------------------------------- | |
398 | // wxXmlInterface | |
399 | // ---------------------------------------------------------------------------- | |
400 | class wxXmlInterface | |
401 | { | |
402 | public: | |
403 | wxXmlInterface() {} | |
404 | ||
405 | const wxClass* FindClass(const wxString& classname) const | |
406 | { | |
407 | for (unsigned int i=0; i<m_classes.GetCount(); i++) | |
408 | if (m_classes[i].GetName() == classname) | |
409 | return &m_classes[i]; | |
410 | return NULL; | |
411 | } | |
412 | ||
413 | void Dump(const wxString& filename); | |
414 | ||
415 | const wxClassArray& GetClasses() const | |
416 | { return m_classes; } | |
417 | ||
418 | unsigned int GetClassesCount() const | |
419 | { return m_classes.GetCount(); } | |
420 | ||
421 | unsigned int GetMethodCount() const | |
422 | { | |
423 | unsigned int methods = 0; | |
424 | for (unsigned i=0; i < m_classes.GetCount(); i++) | |
425 | methods += m_classes[i].GetMethodCount(); | |
426 | return methods; | |
427 | } | |
428 | ||
429 | // pass a full-path header filename: | |
430 | wxClassPtrArray FindClassesDefinedIn(const wxString& headerfile) const; | |
431 | ||
432 | void ShowProgress() | |
433 | { /*wxFprintf(stderr, ".");*/ } | |
434 | ||
435 | // is this interface coherent? | |
436 | bool CheckConsistency() const; | |
437 | ||
438 | protected: | |
439 | wxClassArray m_classes; | |
440 | }; | |
441 | ||
442 | #if 1 | |
443 | // for wxTypeIdHashMap, keys == gccxml IDs and values == associated type strings | |
444 | // e.g. key = "0x123f" and value = "const wxAboutDialogInfo&" | |
445 | WX_DECLARE_HASH_MAP( unsigned long, wxString, | |
446 | wxIntegerHash, wxIntegerEqual, | |
447 | wxTypeIdHashMap ); | |
448 | ||
449 | WX_DECLARE_STRING_HASH_MAP( wxString, wxStringHashMap ); | |
450 | #else | |
451 | #include <map> | |
452 | typedef std::basic_string<char> stlString; | |
453 | typedef std::map<unsigned long, stlString> wxTypeIdHashMap; | |
454 | #endif | |
455 | ||
456 | ||
457 | // ---------------------------------------------------------------------------- | |
458 | // Represents the real interface of wxWidgets | |
459 | // Loads it from the XML produced by gccXML: http://www.gccxml.org | |
460 | // ---------------------------------------------------------------------------- | |
461 | class wxXmlGccInterface : public wxXmlInterface | |
462 | { | |
463 | public: | |
464 | wxXmlGccInterface() | |
465 | { | |
466 | // FIXME: we should retrieve this from the XML file! | |
467 | // here we suppose the XML was created for the currently-running port | |
468 | m_portId = wxPlatformInfo::Get().GetPortId(); | |
469 | } | |
470 | ||
471 | bool Parse(const wxString& filename); | |
472 | bool ParseMethod(const wxXmlNode *p, | |
473 | const wxTypeIdHashMap& types, | |
474 | wxMethod& m); | |
475 | ||
476 | wxPortId GetInterfacePort() const | |
477 | { return m_portId; } | |
478 | ||
479 | wxString GetInterfacePortName() const | |
480 | { return wxPlatformInfo::GetPortIdName(m_portId, false); } | |
481 | ||
482 | protected: | |
483 | // the port for which the gcc XML was generated | |
484 | wxPortId m_portId; | |
485 | }; | |
486 | ||
487 | ||
488 | // ---------------------------------------------------------------------------- | |
489 | // Represents the interface of the doxygen headers of wxWidgets | |
490 | // Loads it from the XML produced by Doxygen: http://www.doxygen.org | |
491 | // ---------------------------------------------------------------------------- | |
492 | class wxXmlDoxygenInterface : public wxXmlInterface | |
493 | { | |
494 | public: | |
495 | wxXmlDoxygenInterface() {} | |
496 | ||
497 | // !!SPEEDUP-TODO!! | |
498 | // Using wxXmlDocument::Load as is, the entire XML file is parsed | |
499 | // and an entire tree of wxXmlNodes is built in memory. | |
500 | // We need however only small portions of the Doxygen-generated XML: to speedup the | |
501 | // processing we could detach the expat callbacks when we detect the beginning of a | |
502 | // node we're not interested about, or just don't create a wxXmlNode for it! | |
503 | // This needs a modification of wxXml API. | |
504 | ||
505 | bool Parse(const wxString& filename); | |
506 | bool ParseCompoundDefinition(const wxString& filename); | |
507 | bool ParseMethod(const wxXmlNode*, wxMethod&, wxString& header); | |
508 | ||
509 | // this class can take advantage of the preprocessor output to give | |
510 | // a minor number of false positive warnings in the final comparison | |
511 | void AddPreprocessorValue(const wxString& name, const wxString& val) | |
512 | { m_preproc[name]=val; } | |
513 | ||
514 | protected: | |
515 | wxStringHashMap m_preproc; | |
516 | }; | |
517 | ||
518 | ||
519 | ||
520 | #endif // _XMLPARSER_H_ | |
521 |