bool ParsePreprocessorOutput(const wxString& filename);
bool Compare();
- int CompareClasses(const wxClass* iface, const wxClassPtrArray& api);
+ int CompareClasses(const wxClass* iface, const wxClass* api);
bool FixMethod(const wxString& header, const wxMethod* iface, const wxMethod* api);
void ShowProgress();
{
const wxClassArray& interfaces = m_doxyInterface.GetClasses();
const wxClass* c;
- wxClassPtrArray api;
int mcount = 0, ccount = 0;
LogMessage("Comparing the interface API to the real API (%d classes to compare)...",
wxString cname = interfaces[i].GetName();
- api.Empty();
-
// search in the real headers for i-th interface class; we search for
// both class cname and cnameBase since in wxWidgets world tipically
// class cname is platform-specific while the real public interface of
// that class is part of the cnameBase class.
- c = m_gccInterface.FindClass(cname);
- if (c) api.Add(c);
- c = m_gccInterface.FindClass(cname + "Base");
- if (c) api.Add(c);
+ /*c = m_gccInterface.FindClass(cname + "Base");
+ if (c) api.Add(c);*/
- // sometimes the platform-specific class is named "wxGeneric" + cname
- // or similar:
- c = m_gccInterface.FindClass("wxGeneric" + cname.Mid(2));
- if (c) api.Add(c);
- c = m_gccInterface.FindClass("wxGtk" + cname.Mid(2));
- if (c) api.Add(c);
+ c = m_gccInterface.FindClass(cname);
+ if (!c)
+ {
+ // sometimes the platform-specific class is named "wxGeneric" + cname
+ // or similar:
+ c = m_gccInterface.FindClass("wxGeneric" + cname.Mid(2));
+ if (!c)
+ {
+ c = m_gccInterface.FindClass("wxGtk" + cname.Mid(2));
+ }
+ }
- if (api.GetCount()>0) {
+ if (c) {
- // there is a class with exactly the same name!
- mcount += CompareClasses(&interfaces[i], api);
+ // there is a class with the same (logic) name!
+ mcount += CompareClasses(&interfaces[i], c);
} else {
return true;
}
-int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClassPtrArray& api)
+int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClass* api)
{
- wxString searchedclasses;
const wxMethod *real;
int count = 0;
- wxASSERT(iface && api.GetCount()>0);
-
- // build a string with the names of the API classes compared to iface
- for (unsigned int j=0; j<api.GetCount(); j++)
- searchedclasses += "/" + api[j]->GetName();
- searchedclasses.Remove(0, 1);
+ wxASSERT(iface && api);
// shorten the name of the header so the log file is more readable
wxString header = wxFileName(iface->GetHeader()).GetFullName();
for (unsigned int i=0; i<iface->GetMethodCount(); i++)
{
const wxMethod& m = iface->GetMethod(i);
- int matches = 0;
// only compare the methods which are available for the port
// for which the gcc XML was produced
}
// search in the methods of the api classes provided
- for (unsigned int j=0; j<api.GetCount(); j++)
- {
- real = api[j]->FindMethod(m);
- if (real)
- matches++; // there is a real matching prototype! It's ok!
- }
+ real = api->RecursiveUpwardFindMethod(m, &m_gccInterface);
- if (matches == 0)
+ if (real)
{
bool exit = false;
- wxMethodPtrArray overloads;
-
- // try searching for methods with the same name but with
- // different return type / arguments / qualifiers
- for (unsigned int j=0; j<api.GetCount(); j++)
- {
- wxMethodPtrArray results = api[j]->FindMethodsNamed(m.GetName());
-
- // append "results" array to "overloads"
- WX_APPEND_ARRAY(overloads, results);
-
+ wxMethodPtrArray overloads =
+ api->RecursiveUpwardFindMethodsNamed(m.GetName(), &m_gccInterface);
#define HACK_TO_AUTO_CORRECT_ONLY_METHOD_ATTRIBUTES 0
#if HACK_TO_AUTO_CORRECT_ONLY_METHOD_ATTRIBUTES
- for (unsigned int k=0; k<results.GetCount(); k++)
- if (results[k]->MatchesExceptForAttributes(m) &&
- results[k]->IsPureVirtual() == m.IsPureVirtual())
- {
- // fix default values of results[k]:
- wxMethod tmp(*results[k]);
- tmp.SetArgumentTypes(m.GetArgumentTypes());
+ for (unsigned int k=0; k<overloads.GetCount(); k++)
+ if (overloads[k]->MatchesExceptForAttributes(m) &&
+ overloads[k]->IsPureVirtual() == m.IsPureVirtual())
+ {
+ // fix default values of results[k]:
+ wxMethod tmp(*overloads[k]);
+ tmp.SetArgumentTypes(m.GetArgumentTypes());
- // modify interface header
- if (FixMethod(iface->GetHeader(), &m, &tmp))
- LogMessage("Adjusted attributes of '%s' method", m.GetAsString());
+ // modify interface header
+ if (FixMethod(iface->GetHeader(), &m, &tmp))
+ LogMessage("Adjusted attributes of '%s' method", m.GetAsString());
- exit = true;
- break;
- }
-
- if (exit)
+ exit = true;
break;
-#endif
- }
+ }
-#if HACK_TO_AUTO_CORRECT_ONLY_METHOD_ATTRIBUTES
if (!exit)
{
#endif
if (overloads.GetCount()==0)
{
- /*
- TODO: sometimes the interface headers re-document a method
- inherited from a base class even if the real header does
- not actually re-implement it.
- To avoid false positives, we'd need to search in the base classes
- of api[] classes and search for a matching method.
- */
- LogMessage("%s: real '%s' class has no method '%s'",
- header, searchedclasses, m.GetAsString());
+ LogMessage("%s: real '%s' class and their parents have no method '%s'",
+ header, api->GetName(), m.GetAsString());
// we've found no overloads
}
else
if (overloads.GetCount()>1)
warning += wxString::Format(": in the real headers there are %d overloads of '%s' for "
"'%s' all with different signatures:\n",
- overloads.GetCount(), m.GetName(), searchedclasses);
+ overloads.GetCount(), m.GetName(), api->GetName());
else
warning += wxString::Format(": in the real headers there is a method '%s' for '%s'"
" but has different signature:\n",
- m.GetName(), searchedclasses);
+ m.GetName(), api->GetName());
// get a list of the prototypes with _all_ possible attributes:
warning += "\tdoxy header: " + m.GetAsString(true, true, true, true);
if (m_strDefaultValueForCmp == "0u")
m_strDefaultValueForCmp = "0";
+ m_strDefaultValue.Replace("0x000000001", "1");
+ m_strDefaultValueForCmp.Replace("0x000000001", "1");
+
// fix for unicode strings:
+ m_strDefaultValue.Replace("\\000\\000\\000", "");
m_strDefaultValueForCmp.Replace("\\000\\000\\000", "");
if (m_strDefaultValueForCmp.StartsWith("wxT(") &&
return NULL;
}
+const wxMethod* wxClass::RecursiveUpwardFindMethod(const wxMethod& m,
+ const wxXmlInterface* allclasses) const
+{
+ // first, search into *this
+ const wxMethod* ret = FindMethod(m);
+ if (ret)
+ return ret;
+
+ // then, search into its parents
+ for (unsigned int i=0; i<m_parents.GetCount(); i++)
+ {
+ // ignore non-wx-classes parents
+ // AD-HOC FIX: discard wxScrolledT_Helper parent as it always gives errors
+ if (m_parents[i].StartsWith("wx") || m_parents[i] == "wxScrolledT_Helper")
+ {
+ const wxClass *parent = allclasses->FindClass(m_parents[i]);
+ if (!parent) {
+ wxLogError("Could not find parent '%s' of class '%s'...",
+ m_parents[i], GetName());
+ return false;
+ }
+
+ const wxMethod *parentMethod = parent->RecursiveUpwardFindMethod(m, allclasses);
+ if (parentMethod)
+ return parentMethod;
+ }
+ }
+
+ // could not find anything even in parent classes...
+ return NULL;
+}
+
wxMethodPtrArray wxClass::FindMethodsNamed(const wxString& name) const
{
wxMethodPtrArray ret;
}
+wxMethodPtrArray wxClass::RecursiveUpwardFindMethodsNamed(const wxString& name,
+ const wxXmlInterface* allclasses) const
+{
+ // first, search into *this
+ wxMethodPtrArray ret = FindMethodsNamed(name);
+ if (ret.GetCount()>0)
+ return ret; // stop here, don't look upward in the parents
+
+ // then, search into parents of this class
+ for (unsigned int i=0; i<m_parents.GetCount(); i++)
+ {
+ // AD-HOC FIX: discard wxScrolledT_Helper parent as it always gives errors
+ if (m_parents[i].StartsWith("wx") || m_parents[i] == "wxScrolledT_Helper")
+ {
+ const wxClass *parent = allclasses->FindClass(m_parents[i]);
+ if (!parent) {
+ wxLogError("Could not find parent '%s' of class '%s'...",
+ m_parents[i], GetName());
+ return false;
+ }
+
+ wxMethodPtrArray temp = parent->RecursiveUpwardFindMethodsNamed(name, allclasses);
+ WX_APPEND_ARRAY(ret, temp);
+ }
+ }
+
+ return ret;
+}
+
+
+
// ----------------------------------------------------------------------------
// wxXmlInterface
// ----------------------------------------------------------------------------
#define ATTRIB_POINTER 4
#define ATTRIB_ARRAY 8
+// it may sound strange but gccxml, in order to produce shorter ID names
+// uses (after the underscore) characters in range 0-9 and a-z in the ID names;
+// in order to be able to translate such strings into numbers using strtoul()
+// we use as base 10 (possible digits) + 25 (possible characters) = 35
#define GCCXML_BASE 35
class toResolveTypeItem
WX_DECLARE_HASH_MAP( unsigned long, wxClass*,
wxIntegerHash, wxIntegerEqual,
wxClassMemberIdHashMap );
+
#else
#include <map>
typedef std::map<unsigned long, toResolveTypeItem> wxToResolveTypeHashMap;
// NB: "file" attribute contains an ID value that we'll resolve later
m_classes.Add(wxClass(cname, child->GetAttribute("file")));
+ // the just-inserted class:
+ wxClass *newClass = &m_classes.Last();
+
+ // now get a list of the base classes:
+ wxXmlNode *baseNode = child->GetChildren();
+ while (baseNode)
+ {
+ // for now we store as "parents" only the parent IDs...
+ // later we will resolve them into full class names
+ if (baseNode->GetName() == "Base")
+ newClass->AddParent(baseNode->GetAttribute("type"));
+
+ baseNode = baseNode->GetNext();
+ }
+
const wxString& ids = child->GetAttribute("members");
if (ids.IsEmpty())
{
else
{
// decode the non-empty list of IDs:
- if (!getMemberIDs(&members, &m_classes.Last(), ids)) {
+ if (!getMemberIDs(&members, newClass, ids)) {
LogError("Invalid member IDs for '%s' class node: %s",
cname, child->GetAttribute("id"));
return false;
m_classes[i].SetHeader(idx->second);
}
+ // resolve parent names
+ for (unsigned int i=0; i<m_classes.GetCount(); i++)
+ {
+ for (unsigned int k=0; k<m_classes[i].GetParentCount(); k++)
+ {
+ unsigned long id;
+
+ if (!getID(&id, m_classes[i].GetParent(k))) {
+ LogError("invalid parent class ID for '%s'", m_classes[i].GetName());
+ return false;
+ }
+
+ wxTypeIdHashMap::const_iterator idx = types.find(id);
+ if (idx == types.end())
+ {
+ // this is an error!
+ LogError("couldn't find parent class ID '%d'", id);
+ }
+ else
+ // replace k-th parent with its true name:
+ m_classes[i].SetParent(k, idx->second);
+ }
+ }
+
// build the list of the wx methods
child = doc.GetRoot()->GetChildren();
while (child)
bool wxXmlDoxygenInterface::ParseCompoundDefinition(const wxString& filename)
{
+ wxClassMemberIdHashMap parents;
wxXmlDocument doc;
wxXmlNode *child;
int nodes = 0;
// identify <onlyfor> custom XML tags
klass.SetAvailability(GetAvailabilityFor(subchild));
}
+ else if (subchild->GetName() == "basecompoundref")
+ {
+ // add the name of this parent to the list of klass' parents
+ klass.AddParent(subchild->GetNodeContent());
+ }
subchild = subchild->GetNext();
}
WX_DEFINE_ARRAY(const wxMethod*, wxMethodPtrArray);
+// we need wxClassPtrArray to be defined _before_ wxClass itself,
+// since wxClass uses wxClassPtrArray.
+class wxClass;
+WX_DEFINE_ARRAY(const wxClass*, wxClassPtrArray);
+
+class wxXmlInterface;
+
+
// ----------------------------------------------------------------------------
// Represents a class of the wx API/interface.
// ----------------------------------------------------------------------------
{ m_strName=name; }
void SetAvailability(int nAvail)
{ m_nAvailability=nAvail; }
-
+ void SetParent(unsigned int k, const wxString& name)
+ { m_parents[k]=name; }
public: // getters
int GetAvailability() const
{ return m_nAvailability; }
+ //const wxClass *GetParent(unsigned int i) const
+ const wxString& GetParent(unsigned int i) const
+ { return m_parents[i]; }
+ unsigned int GetParentCount() const
+ { return m_parents.GetCount(); }
+
public: // misc
void AddMethod(const wxMethod& func)
{ m_methods.Add(func); }
+ void AddParent(const wxString& parent)//wxClass* parent)
+ { m_parents.Add(parent); }
+
// returns a single result (the first, which is also the only
// one if CheckConsistency() return true)
const wxMethod* FindMethod(const wxMethod& m) const;
+ // like FindMethod() but this one searches also recursively in
+ // the parents of this class.
+ const wxMethod* RecursiveUpwardFindMethod(const wxMethod& m,
+ const wxXmlInterface* allclasses) const;
+
// returns an array of pointers to the overloaded methods with the
// same given name
- wxMethodPtrArray FindMethodsNamed(const wxString& m) const;
+ wxMethodPtrArray FindMethodsNamed(const wxString& name) const;
+
+ // like FindMethodsNamed() but this one searches also recursively in
+ // the parents of this class.
+ wxMethodPtrArray RecursiveUpwardFindMethodsNamed(const wxString& name,
+ const wxXmlInterface* allclasses) const;
// dumps all methods to the given output stream
void Dump(wxTextOutputStream& stream) const;
wxString m_strHeader;
wxMethodArray m_methods;
+ // name of the base classes: we store the names and not the pointers
+ // because this makes _much_ easier the parsing process!
+ // (basically because when parsing class X which derives from Y,
+ // we may have not parsed yet class Y!)
+ wxArrayString m_parents;
+
// see the wxMethod::m_nAvailability field for more info
int m_nAvailability;
};
WX_DECLARE_OBJARRAY(wxClass, wxClassArray);
-WX_DEFINE_ARRAY(const wxClass*, wxClassPtrArray);