m_strType.Replace(" ,", ",");
m_strType = m_strType.Strip(wxString::both);
+
+ // now set the clean version
+ m_strTypeClean = m_strType;
+ m_strTypeClean.Replace("const", "");
+ m_strTypeClean.Replace("static", "");
+ m_strTypeClean.Replace("*", "");
+ m_strTypeClean.Replace("&", "");
+ m_strTypeClean.Replace("[]", "");
+ m_strTypeClean = m_strTypeClean.Strip(wxString::both);
}
bool wxType::IsOk() const
// "reverse_iterator_impl<wxString::const_iterator>" type
// It can also contain commas, * and & operators etc
- return !GetClean().IsEmpty();
-}
-
-wxString wxType::GetClean() const
-{
- wxString ret(m_strType);
- ret.Replace("const", "");
- ret.Replace("static", "");
- ret.Replace("*", "");
- ret.Replace("&", "");
- ret.Replace("[]", "");
- return ret.Strip(wxString::both);
+ return !m_strTypeClean.IsEmpty();
}
bool wxType::operator==(const wxType& m) const
{
// brain-dead comparison:
- if (GetClean() == m.GetClean() &&
+ if (m_strTypeClean == m.m_strTypeClean &&
IsConst() == m.IsConst() &&
IsStatic() == m.IsStatic() &&
IsPointer() == m.IsPointer() &&
// wxArgumentType
// ----------------------------------------------------------------------------
-void wxArgumentType::SetDefaultValue(const wxString& defval)
+void wxArgumentType::SetDefaultValue(const wxString& defval, const wxString& defvalForCmp)
{
- m_strDefaultValue=defval;
+ m_strDefaultValue=defval.Strip(wxString::both);
+ m_strDefaultValueForCmp=defvalForCmp.Strip(wxString::both);
// in order to make valid&simple comparison on argument defaults,
// we reduce some of the multiple forms in which the same things may appear
// to a single form:
- m_strDefaultValue.Replace("0u", "0");
-
+ if (m_strDefaultValue == "0u")
+ m_strDefaultValue = "0";
+/*
if (IsPointer())
m_strDefaultValue.Replace("0", "NULL");
else
m_strDefaultValue.Replace("NULL", "0");
-
+*/
if (m_strDefaultValue.Contains("wxGetTranslation"))
- m_strDefaultValue = wxEmptyString; // TODO: wxGetTranslation gives problems to gccxml
+ m_strDefaultValue = "_(TOFIX)"; // TODO: wxGetTranslation gives problems to gccxml
}
bool wxArgumentType::operator==(const wxArgumentType& m) const
if ((const wxType&)(*this) != (const wxType&)m)
return false;
- if (m_strDefaultValue != m.m_strDefaultValue)
+ const wxString& def1 = m_strDefaultValueForCmp.IsEmpty() ? m_strDefaultValue : m_strDefaultValueForCmp;
+ const wxString& def2 = m.m_strDefaultValueForCmp.IsEmpty() ? m.m_strDefaultValue : m.m_strDefaultValueForCmp;
+
+ if (def1 != def2)
+ {
+ // maybe the default values are numbers.
+ // in this case gccXML gives as default values things like '-0x0000001' instead of just '-1'.
+ // To handle these cases, we try to convert the default value strings to numbers:
+ long def1val, def2val;
+ if (def1.ToLong(&def1val, 0 /* auto-detect */) &&
+ def2.ToLong(&def2val, 0 /* auto-detect */))
+ {
+ if (def1val == def2val)
+ return true; // the default values match
+ }
+
return false;
+ }
// we deliberately avoid checks on the argument name
return false;
}
+ wxASSERT(!m_bPureVirtual || (m_bPureVirtual && m_bVirtual));
+
for (unsigned int i=0; i<m_args.GetCount(); i++)
if (!m_args[i].IsOk()) {
LogError("'%s' method has invalid %d-th argument type: %s",
- m_strName, i, m_args[i].GetAsString());
+ m_strName, i+1, m_args[i].GetAsString());
return false;
}
// NB: the default value of the arguments can contain pretty much everything
// (think to e.g. wxPoint(3+4/2,0) or *wxBLACK or someClass<type>)
- // so we don't do any test on them.
+ // so we don't do any test on their contents
+ if (m_args.GetCount()>0)
+ {
+ bool previousArgHasDefault = m_args[0].HasDefaultValue();
+ for (unsigned int i=1; i<m_args.GetCount(); i++)
+ {
+ if (previousArgHasDefault && !m_args[i].HasDefaultValue()) {
+ LogError("'%s' method has %d-th argument which has no default value "
+ "(while the previous one had one!)",
+ m_strName, i+1);
+ return false;
+ }
+
+ previousArgHasDefault = m_args[i].HasDefaultValue();
+ }
+ }
return true;
}
bool wxXmlInterface::CheckParseResults() const
{
// this check can be quite slow, so do it only for debug releases:
-#ifdef __WXDEBUG__
+//#ifdef __WXDEBUG__
for (unsigned int i=0; i<m_classes.GetCount(); i++)
if (!m_classes[i].CheckConsistency())
return false;
-#endif
+//#endif
return true;
}
+wxClassPtrArray wxXmlInterface::FindClassesDefinedIn(const wxString& headerfile) const
+{
+ wxClassPtrArray ret;
+
+ for (unsigned int i=0; i<m_classes.GetCount(); i++)
+ if (m_classes[i].GetHeader() == headerfile)
+ ret.Add(&m_classes[i]);
+
+ return ret;
+}
+
+
// ----------------------------------------------------------------------------
// wxXmlGccInterface helper declarations
// ----------------------------------------------------------------------------
return false;
}
+ wxString version = doc.GetRoot()->GetAttribute("cvs_revision");
+ bool old = false;
+
+#define MIN_REVISION 120
+
+ if (!version.StartsWith("1."))
+ old = true;
+ if (!old)
+ {
+ unsigned long rev = 0;
+ if (!version.Mid(2).ToULong(&rev))
+ old = true;
+ else
+ if (rev < MIN_REVISION)
+ old = true;
+ }
+
+ if (old)
+ {
+ LogError("The version of GCC-XML used for the creation of %s is too old; "
+ "the cvs_revision attribute of the root node reports '%s', "
+ "minimal required is 1.%d.", filename, version, MIN_REVISION);
+ return false;
+ }
+
wxToResolveTypeHashMap toResolveTypes;
wxClassMemberIdHashMap members;
wxTypeIdHashMap types;
if (ids.IsEmpty())
{
if (child->GetAttribute("incomplete") != "1") {
- LogError("Invalid member IDs for '%s' class node (ID %s)",
+ LogError("Invalid member IDs for '%s' class node: %s",
cname, child->GetAttribute("id"));
return false;
}
{
// decode the non-empty list of IDs:
if (!getMemberIDs(&members, &m_classes.Last(), ids)) {
- LogError("Invalid member IDs for '%s' class node (ID %s)",
+ LogError("Invalid member IDs for '%s' class node: %s",
cname, child->GetAttribute("id"));
return false;
}
else if (n == "File")
{
if (!child->GetAttribute("id").StartsWith("f")) {
- LogError("Unexpected file ID: %s", id);
+ LogError("Unexpected file ID: %s", child->GetAttribute("id"));
return false;
}
// they're never used as return/argument types by wxWidgets methods
if (g_verbose)
- LogWarning("Type '%s' with ID '%s' does not have name attribute", n, id);
+ LogWarning("Type node '%s' with ID '%s' does not have name attribute",
+ n, child->GetAttribute("id"));
types[id] = "TOFIX";
}
// this <Method> node is a method of the i-th class!
wxMethod newfunc;
- if (!ParseMethod(child, types, newfunc))
+ if (!ParseMethod(child, types, newfunc)) {
+ LogError("The method '%s' could not be added to class '%s'",
+ child->GetAttribute("demangled"), p->GetName());
return false;
+ }
if (newfunc.IsCtor() && !p->IsValidCtorForThisClass(newfunc)) {
LogError("The method '%s' does not seem to be a ctor for '%s'",
- newfunc.GetName(), p->GetName());
+ newfunc.GetName(), p->GetName());
return false;
}
if (newfunc.IsDtor() && !p->IsValidDtorForThisClass(newfunc)) {
LogError("The method '%s' does not seem to be a dtor for '%s'",
- newfunc.GetName(), p->GetName());
+ newfunc.GetName(), p->GetName());
return false;
}
if ((++nodes%PROGRESS_RATE)==0) ShowProgress();
}
- //wxPrint("\n");
if (!CheckParseResults())
return false;
m.SetArgumentTypes(argtypes);
m.SetConst(p->GetAttribute("const") == "1");
m.SetStatic(p->GetAttribute("static") == "1");
+
+ // NOTE: gccxml is smart enough to mark as virtual those functions
+ // which are declared virtual in base classes but don't have
+ // the "virtual" keyword explicitely indicated in the derived
+ // classes... so we don't need any further logic for virtuals
+
m.SetVirtual(p->GetAttribute("virtual") == "1");
m.SetPureVirtual(p->GetAttribute("pure_virtual") == "1");
m.SetDeprecated(p->GetAttribute("attributes") == "deprecated");
}
+
+// ----------------------------------------------------------------------------
+// wxXmlDoxygenInterface global helpers
+// ----------------------------------------------------------------------------
+
+static wxString GetTextFromChildren(const wxXmlNode *n)
+{
+ wxString text;
+
+ // consider the tree
+ //
+ // <a><b>this</b> is a <b>string</b></a>
+ //
+ // <a>
+ // |- <b>
+ // | |- this
+ // |- is a
+ // |- <b>
+ // |- string
+ //
+ // unlike wxXmlNode::GetNodeContent() which would return " is a "
+ // this function returns "this is a string"
+
+ wxXmlNode *ref = n->GetChildren();
+ while (ref) {
+ if (ref->GetType() == wxXML_ELEMENT_NODE)
+ text += ref->GetNodeContent();
+ else if (ref->GetType() == wxXML_TEXT_NODE)
+ text += ref->GetContent();
+ else
+ LogWarning("Unexpected node type while getting text from '%s' node", n->GetName());
+
+ ref = ref->GetNext();
+ }
+
+ return text;
+}
+
+static bool HasTextNodeContaining(const wxXmlNode *parent, const wxString& name)
+{
+ if (!parent)
+ return false;
+
+ wxXmlNode *p = parent->GetChildren();
+ while (p)
+ {
+ switch (p->GetType())
+ {
+ case wxXML_TEXT_NODE:
+ if (p->GetContent() == name)
+ return true;
+ break;
+
+ case wxXML_ELEMENT_NODE:
+ // recurse into this node...
+ if (HasTextNodeContaining(p, name))
+ return true;
+ break;
+
+ default:
+ // skip it
+ break;
+ }
+
+ p = p->GetNext();
+ }
+
+ return false;
+}
+
+static const wxXmlNode* FindNodeNamed(const wxXmlNode* parent, const wxString& name)
+{
+ if (!parent)
+ return NULL;
+
+ const wxXmlNode *p = parent->GetChildren();
+ while (p)
+ {
+ if (p->GetName() == name)
+ return p; // found!
+
+ // search recursively in the children of this node
+ const wxXmlNode *ret = FindNodeNamed(p, name);
+ if (ret)
+ return ret;
+
+ p = p->GetNext();
+ }
+
+ return NULL;
+}
+
+int GetAvailabilityFor(const wxXmlNode *node)
+{
+ // identify <onlyfor> custom XML tags
+ const wxXmlNode* onlyfor = FindNodeNamed(node, "onlyfor");
+ if (!onlyfor)
+ return wxPORT_UNKNOWN;
+
+ wxArrayString ports = wxSplit(onlyfor->GetNodeContent(), ',');
+ int nAvail = wxPORT_UNKNOWN;
+ for (unsigned int i=0; i < ports.GetCount(); i++)
+ {
+ if (!ports[i].StartsWith("wx")) {
+ LogError("unexpected port ID '%s'", ports[i]);
+ return false;
+ }
+
+ nAvail |= wxPlatformInfo::GetPortId(ports[i].Mid(2));
+ }
+
+ return nAvail;
+}
+
+
// ----------------------------------------------------------------------------
// wxXmlDoxygenInterface
// ----------------------------------------------------------------------------
return false;
}
+ /*
+ NB: we may need in future to do a version-check here if the
+ format of the XML generated by doxygen changes.
+ For now (doxygen version 1.5.5), this check is not required
+ since AFAIK the XML format never changed since it was introduced.
+ */
+
m_classes.Alloc(ESTIMATED_NUM_CLASSES);
// process files referenced by this index file
{
wxMethod m;
- if (ParseMethod(membernode, m, header))
+ if (!ParseMethod(membernode, m, header)) {
+ LogError("The method '%s' could not be added to class '%s'",
+ m.GetName(), klass.GetName());
+ return false;
+ }
+
+ if (absoluteFile.IsEmpty())
+ absoluteFile = header;
+ else if (header != absoluteFile)
{
- if (absoluteFile.IsEmpty())
- absoluteFile = header;
- else if (header != absoluteFile)
- {
- LogError("The method '%s' is documented in a different "
- "file from others (which belong to '%s') ?",
- header, absoluteFile);
- return false;
- }
-
- klass.AddMethod(m);
+ LogError("The method '%s' is documented in a different "
+ "file from others (which belong to '%s') ?",
+ header, absoluteFile);
+ return false;
}
+
+ klass.AddMethod(m);
}
membernode = membernode->GetNext();
klass.SetHeader(subchild->GetNodeContent());
}*/
+ else if (subchild->GetName() == "detaileddescription")
+ {
+ // identify <onlyfor> custom XML tags
+ klass.SetAvailability(GetAvailabilityFor(subchild));
+ }
subchild = subchild->GetNext();
}
return true;
}
-static wxString GetTextFromChildren(const wxXmlNode *n)
-{
- wxString text;
-
- // consider the tree
- //
- // <a><b>this</b> is a <b>string</b></a>
- //
- // <a>
- // |- <b>
- // | |- this
- // |- is a
- // |- <b>
- // |- string
- //
- // unlike wxXmlNode::GetNodeContent() which would return " is a "
- // this function returns "this is a string"
-
- wxXmlNode *ref = n->GetChildren();
- while (ref) {
- if (ref->GetType() == wxXML_ELEMENT_NODE)
- text += ref->GetNodeContent();
- else if (ref->GetType() == wxXML_TEXT_NODE)
- text += ref->GetContent();
- else
- LogWarning("Unexpected node type while getting text from '%s' node", n->GetName());
-
- ref = ref->GetNext();
- }
-
- return text;
-}
-
-static bool HasTextNodeContaining(const wxXmlNode *parent, const wxString& name)
-{
- wxXmlNode *p = parent->GetChildren();
- while (p)
- {
- switch (p->GetType())
- {
- case wxXML_TEXT_NODE:
- if (p->GetContent() == name)
- return true;
- break;
-
- case wxXML_ELEMENT_NODE:
- // recurse into this node...
- if (HasTextNodeContaining(p, name))
- return true;
- break;
-
- default:
- // skip it
- break;
- }
-
- p = p->GetNext();
- }
-
- return false;
-}
-
bool wxXmlDoxygenInterface::ParseMethod(const wxXmlNode* p, wxMethod& m, wxString& header)
{
wxArgumentTypeArray args;
else if (n->GetName() == "declname")
namestr = GetTextFromChildren(n);
else if (n->GetName() == "defval")
- defstr = GetTextFromChildren(n);
+ defstr = GetTextFromChildren(n).Strip(wxString::both);
else if (n->GetName() == "array")
arrstr = GetTextFromChildren(n);
return false;
}
- args.Add(wxArgumentType(typestr + arrstr, defstr, namestr));
+ wxArgumentType newarg(typestr + arrstr, defstr, namestr);
+
+ // can we use preprocessor output to transform the default value
+ // into the same form which gets processed by wxXmlGccInterface?
+ wxStringHashMap::const_iterator it = m_preproc.find(defstr);
+ if (it != m_preproc.end())
+ newarg.SetDefaultValue(defstr, it->second);
+
+ args.Add(newarg);
}
else if (child->GetName() == "location")
{
// Doxygen outputs somewhere nested inside <detaileddescription>
// a <xreftitle>Deprecated</xreftitle> tag.
m.SetDeprecated(HasTextNodeContaining(child, "Deprecated"));
+
+ // identify <onlyfor> custom XML tags
+ m.SetAvailability(GetAvailabilityFor(child));
}
child = child->GetNext();
m.SetArgumentTypes(args);
m.SetConst(p->GetAttribute("const")=="yes");
m.SetStatic(p->GetAttribute("static")=="yes");
+
+ // NOTE: Doxygen is smart enough to mark as virtual those functions
+ // which are declared virtual in base classes but don't have
+ // the "virtual" keyword explicitely indicated in the derived
+ // classes... so we don't need any further logic for virtuals
+
m.SetVirtual(p->GetAttribute("virt")=="virtual");
m.SetPureVirtual(p->GetAttribute("virt")=="pure-virtual");