BIG CHANGE: added parsing of base classes; now CompareClasses() is much smarter since it looks recursively in the parents of the class being checked;
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55948 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
6b03a638a4
commit
673ae68a3c
@ -79,7 +79,7 @@ public:
|
||||
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();
|
||||
@ -200,7 +200,6 @@ bool IfaceCheckApp::Compare()
|
||||
{
|
||||
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)...",
|
||||
@ -232,28 +231,29 @@ bool IfaceCheckApp::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 + "Base");
|
||||
if (c) api.Add(c);*/
|
||||
|
||||
c = m_gccInterface.FindClass(cname);
|
||||
if (c) api.Add(c);
|
||||
c = m_gccInterface.FindClass(cname + "Base");
|
||||
if (c) api.Add(c);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (c) {
|
||||
|
||||
if (api.GetCount()>0) {
|
||||
|
||||
// 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 {
|
||||
|
||||
@ -271,18 +271,12 @@ bool IfaceCheckApp::Compare()
|
||||
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();
|
||||
@ -290,7 +284,6 @@ int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClassPtrArray& a
|
||||
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
|
||||
@ -305,67 +298,40 @@ int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClassPtrArray& a
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -375,11 +341,11 @@ int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClassPtrArray& a
|
||||
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);
|
||||
|
@ -147,7 +147,11 @@ void wxArgumentType::SetDefaultValue(const wxString& defval, const wxString& def
|
||||
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(") &&
|
||||
@ -480,6 +484,38 @@ const wxMethod* wxClass::FindMethod(const wxMethod& m) const
|
||||
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;
|
||||
@ -492,6 +528,37 @@ wxMethodPtrArray wxClass::FindMethodsNamed(const wxString& name) const
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -554,6 +621,10 @@ wxClassPtrArray wxXmlInterface::FindClassesDefinedIn(const wxString& headerfile)
|
||||
#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
|
||||
@ -578,6 +649,7 @@ WX_DECLARE_HASH_MAP( unsigned long, toResolveTypeItem,
|
||||
WX_DECLARE_HASH_MAP( unsigned long, wxClass*,
|
||||
wxIntegerHash, wxIntegerEqual,
|
||||
wxClassMemberIdHashMap );
|
||||
|
||||
#else
|
||||
#include <map>
|
||||
typedef std::map<unsigned long, toResolveTypeItem> wxToResolveTypeHashMap;
|
||||
@ -732,6 +804,21 @@ bool wxXmlGccInterface::Parse(const wxString& filename)
|
||||
// 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())
|
||||
{
|
||||
@ -746,7 +833,7 @@ bool wxXmlGccInterface::Parse(const wxString& filename)
|
||||
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;
|
||||
@ -950,6 +1037,30 @@ bool wxXmlGccInterface::Parse(const wxString& filename)
|
||||
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)
|
||||
@ -1278,6 +1389,7 @@ bool wxXmlDoxygenInterface::Parse(const wxString& filename)
|
||||
|
||||
bool wxXmlDoxygenInterface::ParseCompoundDefinition(const wxString& filename)
|
||||
{
|
||||
wxClassMemberIdHashMap parents;
|
||||
wxXmlDocument doc;
|
||||
wxXmlNode *child;
|
||||
int nodes = 0;
|
||||
@ -1375,6 +1487,11 @@ bool wxXmlDoxygenInterface::ParseCompoundDefinition(const wxString& filename)
|
||||
// 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();
|
||||
}
|
||||
|
@ -288,6 +288,14 @@ WX_DECLARE_OBJARRAY(wxMethod, wxMethodArray);
|
||||
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.
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -307,7 +315,8 @@ public: // setters
|
||||
{ m_strName=name; }
|
||||
void SetAvailability(int nAvail)
|
||||
{ m_nAvailability=nAvail; }
|
||||
|
||||
void SetParent(unsigned int k, const wxString& name)
|
||||
{ m_parents[k]=name; }
|
||||
|
||||
public: // getters
|
||||
|
||||
@ -333,18 +342,37 @@ 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;
|
||||
@ -357,12 +385,17 @@ protected:
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user