#include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(wxTypeArray)
+WX_DEFINE_OBJARRAY(wxArgumentTypeArray)
WX_DEFINE_OBJARRAY(wxMethodArray)
WX_DEFINE_OBJARRAY(wxClassArray)
// defined in ifacecheck.cpp
extern bool g_verbose;
+// global variable:
+bool g_bLogEnabled = true;
+
// ----------------------------------------------------------------------------
wxType wxEmptyType;
-void wxType::SetFromString(const wxString& t)
+void wxType::SetTypeFromString(const wxString& t)
{
- m_strType = t.Strip(wxString::both);
+ /*
+ TODO: optimize the following code writing a single function
+ which works at char-level and does everything in a single pass
+ */
+
+ m_strType = t;
// [] is the same as * for gccxml
m_strType.Replace("[]", "*");
+ m_strType.Replace("long int", "long"); // in wx typically we never write "long int", just "long"
+
+ // make sure the * and & operator always use the same spacing rules
+ // (to make sure GetAsString() output is always consistent)
+ m_strType.Replace("*", "* ");
+ m_strType.Replace("&", "& ");
+ m_strType.Replace(" *", "*");
+ m_strType.Replace(" &", "&");
+
+ while (m_strType.Contains(" "))
+ m_strType.Replace(" ", " "); // do it once again
+
+ 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);
+
+ // to avoid false errors types like wxStandardPaths and wxStandardPathsBase
+ // need to be considered as the same type
+ if (m_strTypeClean.EndsWith("Base"))
+ m_strTypeClean = m_strTypeClean.Left(m_strTypeClean.Len()-4);
+
+ // ADHOC-FIX:
+ // doxygen likes to put wxDateTime:: in front of all wxDateTime enums;
+ // fix this to avoid false positives
+ m_strTypeClean.Replace("wxDateTime::", "");
+ m_strTypeClean.Replace("wxStockGDI::", ""); // same story for some other classes
}
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() &&
IsReference() == m.IsReference())
return true;
+ if (g_verbose)
+ LogMessage("Type '%s' does not match type '%s'", m_strType, m.m_strType);
+
return false;
}
+
+// ----------------------------------------------------------------------------
+// wxArgumentType
+// ----------------------------------------------------------------------------
+
+void wxArgumentType::SetDefaultValue(const wxString& defval, const wxString& defvalForCmp)
+{
+ m_strDefaultValue = defval.Strip(wxString::both);
+ m_strDefaultValueForCmp = defvalForCmp.IsEmpty() ? m_strDefaultValue : defvalForCmp.Strip(wxString::both);
+
+ // adjust aesthetic form of DefaultValue for the modify mode of ifacecheck:
+ // we may need to write it out in an interface header
+ if (m_strDefaultValue == "0u")
+ m_strDefaultValue = "0";
+
+ // 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:
+ if (m_strDefaultValueForCmp == "0u")
+ m_strDefaultValueForCmp = "0";
+
+ // fix for unicode strings:
+ m_strDefaultValueForCmp.Replace("\\000\\000\\000", "");
+
+ if (m_strDefaultValueForCmp.StartsWith("wxT(") &&
+ m_strDefaultValueForCmp.EndsWith(")"))
+ {
+ // get rid of the wxT() part
+ unsigned int len = m_strDefaultValueForCmp.Len();
+ m_strDefaultValueForCmp = m_strDefaultValueForCmp.Mid(4,len-5);
+ }
+
+/*
+ if (IsPointer())
+ m_strDefaultValueForCmp.Replace("0", "NULL");
+ else
+ m_strDefaultValueForCmp.Replace("NULL", "0");
+*/
+ // ADHOC-FIX:
+ // doxygen likes to put wxDateTime:: in front of all wxDateTime enums;
+ // fix this to avoid false positives
+ m_strDefaultValueForCmp.Replace("wxDateTime::", "");
+ m_strDefaultValueForCmp.Replace("wxStockGDI::", ""); // same story for some other classes
+
+ // ADHOC-FIX:
+ if (m_strDefaultValueForCmp.Contains("wxGetTranslation"))
+ m_strDefaultValueForCmp = "_(TOFIX)"; // TODO: wxGetTranslation gives problems to gccxml
+}
+
+bool wxArgumentType::operator==(const wxArgumentType& m) const
+{
+ if ((const wxType&)(*this) != (const wxType&)m)
+ return false;
+
+ // ADHOC-FIX:
+ // default values for style attributes of wxWindow-derived classes in gccxml appear as raw
+ // numbers; avoid false positives in this case!
+ if (m_strArgName == m.m_strArgName && m_strArgName == "style" &&
+ (m_strDefaultValueForCmp.IsNumber() || m.m_strDefaultValueForCmp.IsNumber()))
+ return true;
+
+ if (m_strDefaultValueForCmp != m.m_strDefaultValueForCmp)
+ {
+ // 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 (m_strDefaultValueForCmp.ToLong(&def1val, 0 /* auto-detect */) &&
+ m.m_strDefaultValueForCmp.ToLong(&def2val, 0 /* auto-detect */))
+ {
+ if (def1val == def2val)
+ return true; // the default values match
+ }
+
+ if (g_verbose)
+ LogMessage("Argument type '%s = %s' has different default value from '%s = %s'",
+ m_strType, m_strDefaultValueForCmp, m.m_strType, m.m_strDefaultValueForCmp);
+ return false;
+ }
+
+ // we deliberately avoid checks on the argument name
+
+ return true;
+}
+
+
// ----------------------------------------------------------------------------
// wxMethod
// ----------------------------------------------------------------------------
return false;
// a function can't be both const and static or virtual and static!
- if ((m_bConst && m_bStatic) || (m_bVirtual && m_bStatic)) {
+ if ((m_bConst && m_bStatic) || ((m_bVirtual || m_bPureVirtual) && m_bStatic)) {
LogError("'%s' method can't be both const/static or virtual/static", m_strName);
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;
}
-void wxMethod::SetArgumentTypes(const wxTypeArray& arr, const wxArrayString& defaults)
+bool wxMethod::MatchesExceptForAttributes(const wxMethod& m) const
{
- wxASSERT(arr.GetCount()==defaults.GetCount());
-
- m_args=arr;
- m_argDefaults=defaults;
+ if (GetReturnType() != m.GetReturnType() ||
+ GetName() != m.GetName())
+ return false;
- // 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
- for (unsigned int i=0; i<m_argDefaults.GetCount(); i++)
- {
- m_argDefaults[i].Replace("NULL", "0");
- m_argDefaults[i].Replace("0u", "0");
+ if (m_args.GetCount()!=m.m_args.GetCount()) {
+ if (g_verbose)
+ LogMessage("Method '%s' has %d arguments while '%s' has %d arguments",
+ m_strName, m_args.GetCount(), m_strName, m.m_args.GetCount());
+ return false;
}
+
+ // compare argument types
+ for (unsigned int i=0; i<m_args.GetCount(); i++)
+ if (m_args[i] != m.m_args[i])
+ return false;
+
+ return true;
}
bool wxMethod::operator==(const wxMethod& m) const
{
- if (GetReturnType() != m.GetReturnType() ||
- GetName() != m.GetName() ||
- IsConst() != m.IsConst() ||
+ // check attributes
+ if (IsConst() != m.IsConst() ||
IsStatic() != m.IsStatic() ||
IsVirtual() != m.IsVirtual() ||
- IsDeprecated() != m.IsDeprecated())
+ IsPureVirtual() != m.IsPureVirtual() ||
+ IsDeprecated() != m.IsDeprecated() ||
+ GetAccessSpecifier() != m.GetAccessSpecifier())
return false;
- if (m_args.GetCount()!=m.m_args.GetCount())
- return false;
-
- for (unsigned int i=0; i<m_args.GetCount(); i++)
- if (m_args[i] != m.m_args[i] || m_argDefaults[i] != m.m_argDefaults[i])
- return false;
-
- return true;
+ // check everything else
+ return MatchesExceptForAttributes(m);
}
-wxString wxMethod::GetAsString() const
+wxString wxMethod::GetAsString(bool bWithArgumentNames, bool bCleanDefaultValues,
+ bool bDeprecated, bool bAccessSpec) const
{
wxString ret;
+ // NOTE: for return and argument types, never use wxType::GetAsCleanString
+ // since in that way we'd miss important decorators like &,*,const etc
+
if (m_retType!=wxEmptyType)
ret += m_retType.GetAsString() + " ";
//else; this is a ctor or dtor
for (unsigned int i=0; i<m_args.GetCount(); i++)
{
ret += m_args[i].GetAsString();
- if (!m_argDefaults[i].IsEmpty())
- ret += " = " + m_argDefaults[i];
+
+ const wxString& name = m_args[i].GetArgumentName();
+ if (bWithArgumentNames && !name.IsEmpty())
+ ret += " " + name;
+
+ const wxString& def = bCleanDefaultValues ?
+ m_args[i].GetDefaultCleanValue() : m_args[i].GetDefaultValue();
+ if (!def.IsEmpty())
+ ret += " = " + def;
+
ret += ", ";
}
ret += " const";
if (m_bStatic)
ret = "static " + ret;
- if (m_bVirtual)
+ if (m_bVirtual || m_bPureVirtual)
ret = "virtual " + ret;
+ if (m_bPureVirtual)
+ ret += " = 0";
+ if (m_bDeprecated && bDeprecated)
+ ret += " [deprecated]";
- // in doxygen headers we don't need wxDEPRECATED:
- //if (m_bDeprecated)
- // ret = "wxDEPRECATED( " + ret + " )";
+ if (bAccessSpec)
+ {
+ switch (m_access)
+ {
+ case wxMAS_PUBLIC:
+ ret += " [public]";
+ break;
+ case wxMAS_PROTECTED:
+ ret += " [protected]";
+ break;
+ case wxMAS_PRIVATE:
+ ret += " [private]";
+ break;
+ }
+ }
return ret;
}
stream << "[" + m_strName + "]";
for (unsigned int i=0; i<m_args.GetCount(); i++)
- stream << "[" + m_args[i].GetAsString() + "=" + m_argDefaults[i] + "]";
+ stream << "[" + m_args[i].GetAsString() + " " + m_args[i].GetArgumentName() +
+ "=" + m_args[i].GetDefaultValue() + "]";
if (IsConst())
stream << " CONST";
stream << " STATIC";
if (IsVirtual())
stream << " VIRTUAL";
+ if (IsPureVirtual())
+ stream << " PURE-VIRTUAL";
if (IsDeprecated())
stream << " DEPRECATED";
LogError("class %s has two methods with the same prototype: '%s'",
m_strName, m_methods[i].GetAsString());
return false;
+ ((wxClass*)this)->m_methods.RemoveAt(j);
+ j--;
}
return true;
return NULL;
}
-wxMethodPtrArray wxClass::FindMethodNamed(const wxString& name) const
+wxMethodPtrArray wxClass::FindMethodsNamed(const wxString& name) const
{
wxMethodPtrArray ret;
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
// ----------------------------------------------------------------------------
+// or-able flags for a toResolveTypeItem->attrib:
#define ATTRIB_CONST 1
#define ATTRIB_REFERENCE 2
#define ATTRIB_POINTER 4
toResolveTypeItem(unsigned int refID, unsigned int attribint)
: ref(refID), attribs(attribint) {}
- unsigned long ref, attribs;
+ unsigned long ref, // the referenced type's ID
+ attribs; // the attributes of this reference
};
#if 1
bool getID(unsigned long *id, const wxStringCharType* str)
{
wxStringCharType *end;
-#if wxUSE_UNICODE_UTF8
- unsigned long val = strtoul(str+1, &end, GCCXML_BASE);
-#else
+#if wxUSE_UNICODE_WCHAR
unsigned long val = wcstoul(str+1, &end, GCCXML_BASE);
+#else
+ unsigned long val = strtoul(str+1, &end, GCCXML_BASE);
#endif
// return true only if scan was stopped by the terminating NUL and
// in nodes like <Class> ones... i.e. numeric values separed by " _" token
bool getMemberIDs(wxClassMemberIdHashMap* map, wxClass* p, const wxStringCharType* str)
{
-#if wxUSE_UNICODE_UTF8
- size_t len = strlen(str);
-#else
+#if wxUSE_UNICODE_WCHAR
size_t len = wcslen(str);
+#else
+ size_t len = strlen(str);
#endif
if (len == 0 || str[0] != '_')
while (curpos < end)
{
// curpos always points to the underscore of the next token to parse:
-#if wxUSE_UNICODE_UTF8
- unsigned long id = strtoul(curpos+1, &nexttoken, GCCXML_BASE);
-#else
+#if wxUSE_UNICODE_WCHAR
unsigned long id = wcstoul(curpos+1, &nexttoken, GCCXML_BASE);
+#else
+ unsigned long id = strtoul(curpos+1, &nexttoken, GCCXML_BASE);
#endif
if ( *nexttoken != ' ' || errno == ERANGE || errno == EINVAL )
return false;
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;
wxTypeIdHashMap files;
+ wxTypeIdHashMap typedefs;
// prealloc quite a lot of memory!
m_classes.Alloc(ESTIMATED_NUM_CLASSES);
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;
}
// register this class also as possible return/argument type:
types[id] = cname;
}
+ else if (n == "Typedef")
+ {
+ unsigned long typeId = 0;
+ if (!getID(&typeId, child->GetAttribute("type"))) {
+ LogError("Invalid type for node %s: %s", n, child->GetAttribute("type"));
+ return false;
+ }
+
+ // this typedef node tell us that every type referenced with the
+ // "typeId" ID should be called with another name:
+ wxString name = child->GetAttribute("name");
+
+ // save this typedef in a separate hashmap...
+ typedefs[typeId] = name;
+
+ types[id] = name;
+ }
else if (n == "PointerType" || n == "ReferenceType" ||
n == "CvQualifiedType" || n == "ArrayType")
{
}
if (argstr.Len() > 0)
- argstr = argstr.Left(argstr.Len()-2);
+ argstr = argstr.Left(argstr.Len()-2); // remove final comma
// these nodes make reference to other types... we'll resolve them later
//toResolveTypes[id] = toResolveTypeItem(ret, 0);
- types[id] = child->GetAttribute("returns") + "(" + argstr + ")";
+ //types[id] = child->GetAttribute("returns") + "(" + argstr + ")";
+
+ types[id] = "TOFIX"; // typically this type will be "fixed" thanks
+ // to a typedef later...
}
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";
}
}
// some nodes with IDs referenced by methods as return/argument types, do reference
- // in turn o ther nodes (see PointerType, ReferenceType and CvQualifierType above);
+ // in turn other nodes (see PointerType, ReferenceType and CvQualifierType above);
// thus we need to resolve their name iteratively:
while (toResolveTypes.size()>0)
{
newtype = newtype + "[]";
// add the resolved type to the list of "primary" types
- types[id] = newtype;
+ if (newtype.Contains("TOFIX") && typedefs[id] != "")
+ types[id] = typedefs[id]; // better use a typedef for this type!
+ else
+ types[id] = newtype;
// this one has been resolved; erase it through its iterator!
toResolveTypes.erase(i);
}
else
{
- LogError("Cannot solve '%s' reference type!", referenced);
+ LogError("Cannot solve '%d' reference type!", referenced);
return false;
}
}
child = doc.GetRoot()->GetChildren();
while (child)
{
- wxString n = child->GetName();
+ wxString n = child->GetName(), acc = child->GetAttribute("access");
- // only register public methods
- if (child->GetAttribute("access") == "public" &&
+ // only register public&protected methods
+ if ((acc == "public" || acc == "protected") &&
(n == "Method" || n == "Constructor" || n == "Destructor" || n == "OperatorMethod"))
{
unsigned long id = 0;
// 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;
+ }
+
+ // do some additional check that we can do only here:
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;
}
// resolve argument types
- wxTypeArray argtypes;
- wxArrayString argdefs;
+ wxArgumentTypeArray argtypes;
wxXmlNode *arg = p->GetChildren();
while (arg)
{
return false;
}
- argtypes.Add(wxType(idx->second));
-
- wxString def = arg->GetAttribute("default");
- if (def.Contains("wxGetTranslation"))
- argdefs.Add(wxEmptyString); // TODO: wxGetTranslation gives problems to gccxml
- else
- argdefs.Add(def);
+ argtypes.Add(wxArgumentType(idx->second,
+ arg->GetAttribute("default"),
+ arg->GetAttribute("name")));
}
arg = arg->GetNext();
m.SetReturnType(ret);
m.SetName(name);
- m.SetArgumentTypes(argtypes, argdefs);
+ 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");
+ // decode access specifier
+ if (p->GetAttribute("access") == "public")
+ m.SetAccessSpecifier(wxMAS_PUBLIC);
+ else if (p->GetAttribute("access") == "protected")
+ m.SetAccessSpecifier(wxMAS_PROTECTED);
+ else if (p->GetAttribute("access") == "private")
+ m.SetAccessSpecifier(wxMAS_PRIVATE);
+
if (!m.IsOk()) {
LogError("The prototype '%s' is not valid!", m.GetAsString());
return false;
}
+
+// ----------------------------------------------------------------------------
+// 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
wxXmlNode *subchild = child->GetChildren();
while (subchild)
{
+ wxString kind = subchild->GetAttribute("kind");
+
+ // parse only public&protected functions:
if (subchild->GetName() == "sectiondef" &&
- subchild->GetAttribute("kind") == "public-func")
+ (kind == "public-func" || kind == "protected-func"))
{
wxXmlNode *membernode = subchild->GetChildren();
{
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 (kind == "public-func")
+ m.SetAccessSpecifier(wxMAS_PUBLIC);
+ else if (kind == "protected-func")
+ m.SetAccessSpecifier(wxMAS_PROTECTED);
+ else if (kind == "private-func")
+ m.SetAccessSpecifier(wxMAS_PRIVATE);
+
+ 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)
{
- wxTypeArray args;
- wxArrayString defs;
+ wxArgumentTypeArray args;
long line;
wxXmlNode *child = p->GetChildren();
m.SetReturnType(wxType(GetTextFromChildren(child)));
else if (child->GetName() == "param")
{
- wxString typestr, defstr, arrstr;
+ wxString typestr, namestr, defstr, arrstr;
wxXmlNode *n = child->GetChildren();
while (n)
{
// if the <type> node has children, they should be all TEXT and <ref> nodes
// and we need to take the text they contain, in the order they appear
typestr = GetTextFromChildren(n);
+ else if (n->GetName() == "declname")
+ namestr = GetTextFromChildren(n);
else if (n->GetName() == "defval")
- // same for the <defval> node
- defstr = GetTextFromChildren(n);
+ defstr = GetTextFromChildren(n).Strip(wxString::both);
else if (n->GetName() == "array")
arrstr = GetTextFromChildren(n);
return false;
}
- args.Add(wxType(typestr + arrstr));
- defs.Add(defstr);
+ 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, defs);
+ 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");
if (!m.IsOk()) {
LogError("The prototype '%s' is not valid!", m.GetAsString());