1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Parser of the API/interface XML files
4 // Author: Francesco Montorsi
7 // Copyright: (c) 2008 Francesco Montorsi
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
18 // for all others, include the necessary headers
22 #include "wx/xml/xml.h"
23 #include "wx/wfstream.h"
24 #include "wx/arrimpl.cpp"
25 #include "wx/dynarray.h"
26 #include "wx/filename.h"
28 #include "xmlparser.h"
30 #define PROGRESS_RATE 1000 // each PROGRESS_RATE nodes processed print a dot
31 #define ESTIMATED_NUM_CLASSES 600 // used by both wxXmlInterface-derived classes to prealloc mem
32 #define ESTIMATED_NUM_TYPES 50000 // used only by wxGccXmlInterface to prealloc mem
33 #define ESTIMATED_NUM_FILES 800 // used only by wxGccXmlInterface to prealloc mem
35 WX_DEFINE_OBJARRAY(wxTypeArray
)
36 WX_DEFINE_OBJARRAY(wxMethodArray
)
37 WX_DEFINE_OBJARRAY(wxClassArray
)
40 // declared in ifacecheck.cpp
41 extern bool g_verbose
;
45 // ----------------------------------------------------------------------------
47 // ----------------------------------------------------------------------------
51 void wxType::SetFromString(const wxString
& t
)
53 m_strType
= t
.Strip(wxString::both
);
55 // [] is the same as * for gccxml
56 m_strType
.Replace("[]", "*");
59 bool wxType::IsOk() const
61 // NB: m_strType can contain the :: operator; think to e.g. the
62 // "reverse_iterator_impl<wxString::const_iterator>" type
63 // It can also contain commas, * and & operators etc
65 return !GetClean().IsEmpty();
68 wxString
wxType::GetClean() const
70 wxString
ret(m_strType
);
71 ret
.Replace("const", "");
72 ret
.Replace("static", "");
75 ret
.Replace("[]", "");
76 return ret
.Strip(wxString::both
);
79 bool wxType::operator==(const wxType
& m
) const
81 // brain-dead comparison:
83 if (GetClean() == m
.GetClean() &&
84 IsConst() == m
.IsConst() &&
85 IsStatic() == m
.IsStatic() &&
86 IsPointer() == m
.IsPointer() &&
87 IsReference() == m
.IsReference())
93 // ----------------------------------------------------------------------------
95 // ----------------------------------------------------------------------------
97 bool wxMethod::IsOk() const
99 // NOTE: m_retType can be a wxEmptyType, and means that this method
100 // is a ctor or a dtor.
101 if (!m_retType
.IsOk() && m_retType
!=wxEmptyType
) {
102 LogError("'%s' method has invalid return type: %s", m_retType
.GetAsString());
106 if (m_strName
.IsEmpty())
109 // a function can't be both const and static or virtual and static!
110 if ((m_bConst
&& m_bStatic
) || (m_bVirtual
&& m_bStatic
)) {
111 LogError("'%s' method can't be both const/static or virtual/static", m_strName
);
115 for (unsigned int i
=0; i
<m_args
.GetCount(); i
++)
116 if (!m_args
[i
].IsOk()) {
117 LogError("'%s' method has invalid %d-th argument type: %s",
118 m_strName
, i
, m_args
[i
].GetAsString());
122 // NB: the default value of the arguments can contain pretty much everything
123 // (think to e.g. wxPoint(3+4/2,0) or *wxBLACK or someClass<type>)
124 // so we don't do any test on them.
129 void wxMethod::SetArgumentTypes(const wxTypeArray
& arr
, const wxArrayString
& defaults
)
131 wxASSERT(arr
.GetCount()==defaults
.GetCount());
134 m_argDefaults
=defaults
;
136 // in order to make valid&simple comparison on argument defaults,
137 // we reduce some of the multiple forms in which the same things may appear
139 for (unsigned int i
=0; i
<m_argDefaults
.GetCount(); i
++)
141 m_argDefaults
[i
].Replace("NULL", "0");
142 m_argDefaults
[i
].Replace("0u", "0");
146 bool wxMethod::operator==(const wxMethod
& m
) const
148 if (GetReturnType() != m
.GetReturnType() ||
149 GetName() != m
.GetName() ||
150 IsConst() != m
.IsConst() ||
151 IsStatic() != m
.IsStatic() ||
152 IsVirtual() != m
.IsVirtual())
155 if (m_args
.GetCount()!=m
.m_args
.GetCount())
158 for (unsigned int i
=0; i
<m_args
.GetCount(); i
++)
159 if (m_args
[i
] != m
.m_args
[i
] || m_argDefaults
[i
] != m
.m_argDefaults
[i
])
165 wxString
wxMethod::GetAsString() const
169 if (m_retType
!=wxEmptyType
)
170 ret
+= m_retType
.GetAsString() + " ";
171 //else; this is a ctor or dtor
173 ret
+= m_strName
+ "(";
175 for (unsigned int i
=0; i
<m_args
.GetCount(); i
++)
177 ret
+= m_args
[i
].GetAsString();
178 if (!m_argDefaults
[i
].IsEmpty())
179 ret
+= " = " + m_argDefaults
[i
];
183 if (m_args
.GetCount()>0)
191 ret
= "static " + ret
;
193 ret
= "virtual " + ret
;
198 void wxMethod::Dump(wxTextOutputStream
& stream
) const
200 stream
<< "[" + m_retType
.GetAsString() + "]";
201 stream
<< "[" + m_strName
+ "]";
203 for (unsigned int i
=0; i
<m_args
.GetCount(); i
++)
204 stream
<< "[" + m_args
[i
].GetAsString() + "=" + m_argDefaults
[i
] + "]";
211 stream
<< " VIRTUAL";
216 // ----------------------------------------------------------------------------
218 // ----------------------------------------------------------------------------
220 wxString
wxClass::GetNameWithoutTemplate() const
222 // NB: I'm not sure this is the right terminology for this function!
224 if (m_strName
.Contains("<"))
225 return m_strName
.Left(m_strName
.Find("<"));
229 bool wxClass::IsValidCtorForThisClass(const wxMethod
& m
) const
231 // remember that e.g. the ctor for wxWritableCharTypeBuffer<wchar_t> is
232 // named wxWritableCharTypeBuffer, without the <...> part!
234 if (m
.IsCtor() && m
.GetName() == GetNameWithoutTemplate())
240 bool wxClass::IsValidDtorForThisClass(const wxMethod
& m
) const
242 if (m
.IsDtor() && m
.GetName() == "~" + GetNameWithoutTemplate())
248 void wxClass::Dump(wxTextOutputStream
& out
) const
250 out
<< m_strName
+ "\n";
252 for (unsigned int i
=0; i
<m_methods
.GetCount(); i
++) {
254 // dump all our methods
256 m_methods
[i
].Dump(out
);
263 bool wxClass::CheckConsistency() const
265 for (unsigned int i
=0; i
<m_methods
.GetCount(); i
++)
266 for (unsigned int j
=0; j
<m_methods
.GetCount(); j
++)
267 if (i
!=j
&& m_methods
[i
] == m_methods
[j
])
269 LogError("class %s has two methods with the same prototype: '%s'",
270 m_strName
, m_methods
[i
].GetAsString());
277 const wxMethod
* wxClass::FindMethod(const wxMethod
& m
) const
279 for (unsigned int i
=0; i
<m_methods
.GetCount(); i
++)
280 if (m_methods
[i
] == m
)
281 return &m_methods
[i
];
285 wxMethodPtrArray
wxClass::FindMethodNamed(const wxString
& name
) const
287 wxMethodPtrArray ret
;
289 for (unsigned int i
=0; i
<m_methods
.GetCount(); i
++)
290 if (m_methods
[i
].GetName() == name
)
291 ret
.Add(&m_methods
[i
]);
297 // ----------------------------------------------------------------------------
299 // ----------------------------------------------------------------------------
301 WX_DEFINE_SORTED_ARRAY(wxClass
*, wxSortedClassArray
);
303 int CompareWxClassObjects(wxClass
*item1
, wxClass
*item2
)
305 // sort alphabetically
306 return item1
->GetName().Cmp(item2
->GetName());
309 void wxXmlInterface::Dump(const wxString
& filename
)
311 wxFFileOutputStream
apioutput( filename
);
312 wxTextOutputStream
apiout( apioutput
);
314 // dump the classes in alphabetical order
315 wxSortedClassArray
sorted(CompareWxClassObjects
);
316 sorted
.Alloc(m_classes
.GetCount());
317 for (unsigned int i
=0; i
<m_classes
.GetCount(); i
++)
318 sorted
.Add(&m_classes
[i
]);
320 // now they have been sorted
321 for (unsigned int i
=0; i
<sorted
.GetCount(); i
++)
322 sorted
[i
]->Dump(apiout
);
325 bool wxXmlInterface::CheckParseResults() const
327 // this check can be quite slow, so do it only for debug releases:
329 for (unsigned int i
=0; i
<m_classes
.GetCount(); i
++)
330 if (!m_classes
[i
].CheckConsistency())
337 // ----------------------------------------------------------------------------
339 // ----------------------------------------------------------------------------
341 #define ATTRIB_CONST 1
342 #define ATTRIB_REFERENCE 2
343 #define ATTRIB_POINTER 4
344 #define ATTRIB_ARRAY 8
346 #define GCCXML_BASE 35
348 class toResolveTypeItem
351 toResolveTypeItem() { attribs
=0; }
352 toResolveTypeItem(unsigned int refID
, unsigned int attribint
)
353 : ref(refID
), attribs(attribint
) {}
355 unsigned long ref
, attribs
;
359 WX_DECLARE_HASH_MAP( unsigned long, toResolveTypeItem
,
360 wxIntegerHash
, wxIntegerEqual
,
361 wxToResolveTypeHashMap
);
364 typedef std::map
<unsigned long, toResolveTypeItem
> wxToResolveTypeHashMap
;
367 bool wxXmlGccInterface::Parse(const wxString
& filename
)
373 LogMessage("Parsing %s...", filename
);
375 if (!doc
.Load(filename
)) {
376 LogError("can't load %s", filename
);
380 // start processing the XML file
381 if (doc
.GetRoot()->GetName() != "GCC_XML") {
382 LogError("invalid root node for %s", filename
);
386 wxToResolveTypeHashMap toResolveTypes
;
387 wxArrayString arrMemberIds
;
388 wxTypeIdHashMap types
;
389 wxTypeIdHashMap files
;
391 // prealloc quite a lot of memory!
392 m_classes
.Alloc(ESTIMATED_NUM_CLASSES
);
393 arrMemberIds
.Alloc(ESTIMATED_NUM_TYPES
);
395 // build a list of wx classes and in general of all existent types
396 child
= doc
.GetRoot()->GetChildren();
399 const wxString
& n
= child
->GetName();
400 //const wxString& id = child->GetAttribute("id");
401 unsigned long id
= 0;
402 if (!child
->GetAttribute("id").Mid(1).ToULong(&id
, GCCXML_BASE
) ||
403 (id
== 0 && n
!= "File")) {
405 // NOTE: <File> nodes can have an id == "f0"...
407 LogError("Invalid id for node %s: %s", n
, child
->GetAttribute("id"));
413 wxString cname
= child
->GetAttribute("name");
414 if (cname
.IsEmpty()) {
415 LogError("Invalid empty name for '%s' node", n
);
419 // only register wx classes (do remember also the IDs of their members)
420 if (cname
.StartsWith("wx")) {
421 arrMemberIds
.Add(child
->GetAttribute("members"));
423 // NB: "file" attribute contains an ID value that we'll resolve later
424 m_classes
.Add(wxClass(cname
, child
->GetAttribute("file")));
427 // register this class also as possible return/argument type:
430 else if (n
== "PointerType" || n
== "ReferenceType" ||
431 n
== "CvQualifiedType" || n
== "ArrayType")
433 unsigned long type
= 0;
434 if (!child
->GetAttribute("type").Mid(1).ToULong(&type
, GCCXML_BASE
) || type
== 0) {
435 LogError("Invalid type for node %s: %s", n
, child
->GetAttribute("type"));
439 unsigned long attr
= 0;
440 if (n
== "PointerType")
441 attr
= ATTRIB_POINTER
;
442 else if (n
== "ReferenceType")
443 attr
= ATTRIB_REFERENCE
;
444 else if (n
== "CvQualifiedType" && child
->GetAttribute("const") == "1")
446 else if (n
== "ArrayType")
449 // these nodes make reference to other types... we'll resolve them later
450 toResolveTypes
[id
] = toResolveTypeItem(type
, attr
);
452 else if (n
== "FunctionType" || n
== "MethodType")
454 /* TODO: incomplete */
456 unsigned long ret
= 0;
457 if (!child
->GetAttribute("returns").Mid(1).ToULong(&ret
, GCCXML_BASE
) || ret
== 0) {
458 LogError("Invalid empty returns value for '%s' node", n
);
462 // these nodes make reference to other types... we'll resolve them later
463 toResolveTypes
[id
] = toResolveTypeItem(ret
, 0);
465 else if (n
== "File")
467 if (!child
->GetAttribute("id").StartsWith("f")) {
468 LogError("Unexpected file ID: %s", id
);
472 // just ignore this node... all file IDs/names were already parsed
473 files
[id
] = child
->GetAttribute("name");
477 // we register everything else as a possible return/argument type:
478 const wxString
& name
= child
->GetAttribute("name");
483 //typeNames.Add(name);
488 // this may happen with unnamed structs/union, special ctors,
489 // or other exotic things which we are not interested to, since
490 // they're never used as return/argument types by wxWidgets methods
493 LogWarning("Type '%s' with ID '%s' does not have name attribute", n
, id
);
499 child
= child
->GetNext();
501 // give feedback to the user about the progress...
502 if ((++nodes%PROGRESS_RATE
)==0) ShowProgress();
505 // some nodes with IDs referenced by methods as return/argument types, do reference
506 // in turn o ther nodes (see PointerType, ReferenceType and CvQualifierType above);
507 // thus we need to resolve their name iteratively:
508 while (toResolveTypes
.size()>0)
511 LogMessage("%d types were collected; %d types need yet to be resolved...",
512 types
.size(), toResolveTypes
.size());
514 for (wxToResolveTypeHashMap::iterator i
= toResolveTypes
.begin();
515 i
!= toResolveTypes
.end();)
517 unsigned long id
= i
->first
;
518 unsigned long referenced
= i
->second
.ref
;
520 wxTypeIdHashMap::iterator primary
= types
.find(referenced
);
521 if (primary
!= types
.end())
523 // this to-resolve-type references a "primary" type
526 int attribs
= i
->second
.attribs
;
528 if (attribs
& ATTRIB_CONST
)
529 newtype
= "const " + primary
->second
;
530 if (attribs
& ATTRIB_REFERENCE
)
531 newtype
= primary
->second
+ "&";
532 if (attribs
& ATTRIB_POINTER
)
533 newtype
= primary
->second
+ "*";
534 if (attribs
& ATTRIB_ARRAY
)
535 newtype
= primary
->second
+ "[]";
537 // add the resolved type to the list of "primary" types
540 // this one has been resolved; erase it through its iterator!
541 toResolveTypes
.erase(i
);
543 // now iterator i is invalid; assign it again to the beginning
544 i
= toResolveTypes
.begin();
548 // then search in the referenced types themselves:
549 wxToResolveTypeHashMap::iterator idx2
= toResolveTypes
.find(referenced
);
550 if (idx2
!= toResolveTypes
.end())
552 // merge this to-resolve-type with the idx2->second type
553 i
->second
.ref
= idx2
->second
.ref
;
554 i
->second
.attribs
|= idx2
->second
.attribs
;
556 // this type will eventually be solved in the next while() iteration
562 LogError("Cannot solve '%s' reference type!", referenced
);
565 typeIds
.Add(toResolveTypeIds
[i
]);
566 typeNames
.Add("TOFIX");
568 // this one has been resolved!
569 toResolveTypeIds
.RemoveAt(i
);
570 toResolveRefType
.RemoveAt(i
);
571 toResolveAttrib
.RemoveAt(i
);
579 // resolve header names
580 for (unsigned int i
=0; i
<m_classes
.GetCount(); i
++)
582 unsigned long fileID
= 0;
583 if (!m_classes
[i
].GetHeader().Mid(1).ToULong(&fileID
, GCCXML_BASE
) || fileID
== 0) {
584 LogError("invalid header id: %s", m_classes
[i
].GetHeader());
589 wxTypeIdHashMap::const_iterator idx
= files
.find(fileID
);
590 if (idx
== files
.end())
593 LogError("couldn't find file ID '%s'", m_classes
[i
].GetHeader());
596 m_classes
[i
].SetHeader(idx
->second
);
599 // build the list of the wx methods
600 child
= doc
.GetRoot()->GetChildren();
603 wxString n
= child
->GetName();
605 if (n
== "Method" || n
== "Constructor" || n
== "Destructor" || n
== "OperatorMethod")
607 wxString id
= child
->GetAttribute("id");
609 // only register public methods
610 if (child
->GetAttribute("access") == "public")
612 wxASSERT(arrMemberIds
.GetCount()==m_classes
.GetCount());
614 for (unsigned int i
=0; i
<m_classes
.GetCount(); i
++)
616 if (arrMemberIds
[i
].Contains(id
))
618 // this <Method> node is a method of the i-th class!
620 if (!ParseMethod(child
, types
, newfunc
))
623 if (newfunc
.IsCtor() && !m_classes
[i
].IsValidCtorForThisClass(newfunc
)) {
624 LogError("The method '%s' does not seem to be a ctor for '%s'",
625 newfunc
.GetName(), m_classes
[i
].GetName());
628 if (newfunc
.IsDtor() && !m_classes
[i
].IsValidDtorForThisClass(newfunc
)) {
629 LogError("The method '%s' does not seem to be a dtor for '%s'",
630 newfunc
.GetName(), m_classes
[i
].GetName());
634 m_classes
[i
].AddMethod(newfunc
);
640 child
= child
->GetNext();
642 // give feedback to the user about the progress...
643 if ((++nodes%PROGRESS_RATE
)==0) ShowProgress();
647 if (!CheckParseResults())
653 bool wxXmlGccInterface::ParseMethod(const wxXmlNode
*p
,
654 const wxTypeIdHashMap
& types
,
658 wxString name
= p
->GetAttribute("name").Strip(wxString::both
);
659 if (p
->GetName() == "Destructor")
661 else if (p
->GetName() == "OperatorMethod")
662 name
= "operator" + name
;
664 // resolve return type
666 unsigned long retid
= 0;
667 if (!p
->GetAttribute("returns").Mid(1).ToULong(&retid
, GCCXML_BASE
) || retid
== 0)
669 if (p
->GetName() != "Destructor" && p
->GetName() != "Constructor") {
670 LogError("Empty return ID for method '%s', with ID '%s'",
671 name
, p
->GetAttribute("id"));
677 wxTypeIdHashMap::const_iterator retidx
= types
.find(retid
);
678 if (retidx
== types
.end()) {
679 LogError("Could not find return type ID '%s'", retid
);
683 ret
= wxType(retidx
->second
);
685 LogError("Invalid return type '%s' for method '%s', with ID '%s'",
686 retidx
->second
, name
, p
->GetAttribute("id"));
691 // resolve argument types
692 wxTypeArray argtypes
;
693 wxArrayString argdefs
;
694 wxXmlNode
*arg
= p
->GetChildren();
697 if (arg
->GetName() == "Argument")
699 unsigned long id
= 0;
700 if (!arg
->GetAttribute("type").Mid(1).ToULong(&id
, GCCXML_BASE
) || id
== 0) {
701 LogError("Invalid argument type ID '%s' for method '%s' with ID %s",
702 arg
->GetAttribute("type"), name
, p
->GetAttribute("id"));
706 wxTypeIdHashMap::const_iterator idx
= types
.find(id
);
707 if (idx
== types
.end()) {
708 LogError("Could not find argument type ID '%s'", id
);
712 argtypes
.Add(wxType(idx
->second
));
714 wxString def
= arg
->GetAttribute("default");
715 if (def
.Contains("wxGetTranslation"))
716 argdefs
.Add(wxEmptyString
); // TODO: wxGetTranslation gives problems to gccxml
721 arg
= arg
->GetNext();
724 m
.SetReturnType(ret
);
726 m
.SetArgumentTypes(argtypes
, argdefs
);
727 m
.SetConst(p
->GetAttribute("const") == "1");
728 m
.SetStatic(p
->GetAttribute("static") == "1");
729 m
.SetVirtual(p
->GetAttribute("virtual") == "1");
732 LogError("The prototype '%s' is not valid!", m
.GetAsString());
740 // ----------------------------------------------------------------------------
741 // wxXmlDoxygenInterface
742 // ----------------------------------------------------------------------------
744 bool wxXmlDoxygenInterface::Parse(const wxString
& filename
)
749 LogMessage("Parsing %s...", filename
);
751 if (!index
.Load(filename
)) {
752 LogError("can't load %s", filename
);
756 // start processing the index:
757 if (index
.GetRoot()->GetName() != "doxygenindex") {
758 LogError("invalid root node for %s", filename
);
762 m_classes
.Alloc(ESTIMATED_NUM_CLASSES
);
764 // process files referenced by this index file
765 compound
= index
.GetRoot()->GetChildren();
768 if (compound
->GetName() == "compound" &&
769 compound
->GetAttribute("kind") == "class")
771 wxString refid
= compound
->GetAttribute("refid");
773 wxFileName
fn(filename
);
774 if (!ParseCompoundDefinition(fn
.GetPath(wxPATH_GET_SEPARATOR
) + refid
+ ".xml"))
778 compound
= compound
->GetNext();
782 if (!CheckParseResults())
788 bool wxXmlDoxygenInterface::ParseCompoundDefinition(const wxString
& filename
)
795 LogMessage("Parsing %s...", filename
);
797 if (!doc
.Load(filename
)) {
798 LogError("can't load %s", filename
);
802 // start processing this compound definition XML
803 if (doc
.GetRoot()->GetName() != "doxygen") {
804 LogError("invalid root node for %s", filename
);
808 // build a list of wx classes
809 child
= doc
.GetRoot()->GetChildren();
812 if (child
->GetName() == "compounddef" &&
813 child
->GetAttribute("kind") == "class")
817 wxString absoluteFile
, header
;
819 wxXmlNode
*subchild
= child
->GetChildren();
822 if (subchild
->GetName() == "sectiondef" &&
823 subchild
->GetAttribute("kind") == "public-func")
826 wxXmlNode
*membernode
= subchild
->GetChildren();
829 if (membernode
->GetName() == "memberdef" &&
830 membernode
->GetAttribute("kind") == "function")
834 if (ParseMethod(membernode
, m
, header
))
836 if (absoluteFile
.IsEmpty())
837 absoluteFile
= header
;
838 else if (header
!= absoluteFile
)
840 LogError("The method '%s' is documented in a different "
841 "file from others (which belong to '%s') ?",
842 header
, absoluteFile
);
850 membernode
= membernode
->GetNext();
853 // all methods of this class were taken from the header "absoluteFile":
854 klass
.SetHeader(absoluteFile
);
856 else if (subchild
->GetName() == "compoundname")
858 klass
.SetName(subchild
->GetNodeContent());
860 /*else if (subchild->GetName() == "includes")
862 // NOTE: we'll get the header from the <location> tags
863 // scattered inside <memberdef> tags instead of
864 // this <includes> tag since it does not contain
865 // the absolute path of the header
867 klass.SetHeader(subchild->GetNodeContent());
870 subchild
= subchild
->GetNext();
875 m_classes
.Add(klass
);
877 LogWarning("discarding class '%s' with %d methods...",
878 klass
.GetName(), klass
.GetMethodCount());
881 child
= child
->GetNext();
883 // give feedback to the user about the progress...
884 if ((++nodes%PROGRESS_RATE
)==0) ShowProgress();
890 static wxString
GetTextFromChildren(const wxXmlNode
*n
)
896 // <a><b>this</b> is a <b>string</b></a>
905 // unlike wxXmlNode::GetNodeContent() which would return " is a "
906 // this function returns "this is a string"
908 wxXmlNode
*ref
= n
->GetChildren();
910 if (ref
->GetType() == wxXML_ELEMENT_NODE
)
911 text
+= ref
->GetNodeContent();
912 else if (ref
->GetType() == wxXML_TEXT_NODE
)
913 text
+= ref
->GetContent();
915 LogWarning("Unexpected node type while getting text from '%s' node", n
->GetName());
917 ref
= ref
->GetNext();
923 bool wxXmlDoxygenInterface::ParseMethod(const wxXmlNode
* p
, wxMethod
& m
, wxString
& header
)
929 wxXmlNode
*child
= p
->GetChildren();
932 if (child
->GetName() == "name")
933 m
.SetName(child
->GetNodeContent());
934 else if (child
->GetName() == "type")
935 m
.SetReturnType(wxType(GetTextFromChildren(child
)));
936 else if (child
->GetName() == "param")
938 wxString typestr
, defstr
, arrstr
;
939 wxXmlNode
*n
= child
->GetChildren();
942 if (n
->GetName() == "type")
943 // if the <type> node has children, they should be all TEXT and <ref> nodes
944 // and we need to take the text they contain, in the order they appear
945 typestr
= GetTextFromChildren(n
);
946 else if (n
->GetName() == "defval")
947 // same for the <defval> node
948 defstr
= GetTextFromChildren(n
);
949 else if (n
->GetName() == "array")
950 arrstr
= GetTextFromChildren(n
);
955 if (typestr
.IsEmpty()) {
956 LogError("cannot find type node for a param in method '%s'", m
.GetName());
960 args
.Add(wxType(typestr
+ arrstr
));
963 else if (child
->GetName() == "location")
965 if (child
->GetAttribute("line").ToLong(&line
))
966 m
.SetLocation((int)line
);
967 header
= child
->GetAttribute("file");
970 child
= child
->GetNext();
973 m
.SetArgumentTypes(args
, defs
);
974 m
.SetConst(p
->GetAttribute("const")=="yes");
975 m
.SetStatic(p
->GetAttribute("static")=="yes");
976 m
.SetVirtual(p
->GetAttribute("virt")=="virtual");
979 LogError("The prototype '%s' is not valid!", m
.GetAsString());