From 673ae68a3c63f85da2f58f50c858efb9deeff79c Mon Sep 17 00:00:00 2001 From: Francesco Montorsi Date: Mon, 29 Sep 2008 16:11:23 +0000 Subject: [PATCH] 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 --- utils/ifacecheck/src/ifacecheck.cpp | 112 +++++++++----------------- utils/ifacecheck/src/xmlparser.cpp | 119 +++++++++++++++++++++++++++- utils/ifacecheck/src/xmlparser.h | 39 ++++++++- 3 files changed, 193 insertions(+), 77 deletions(-) diff --git a/utils/ifacecheck/src/ifacecheck.cpp b/utils/ifacecheck/src/ifacecheck.cpp index 5e03123d25..f7df0abaa8 100644 --- a/utils/ifacecheck/src/ifacecheck.cpp +++ b/utils/ifacecheck/src/ifacecheck.cpp @@ -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; jGetName(); - 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; iGetMethodCount(); 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; jFindMethod(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; jFindMethodsNamed(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; kMatchesExceptForAttributes(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; kMatchesExceptForAttributes(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); diff --git a/utils/ifacecheck/src/xmlparser.cpp b/utils/ifacecheck/src/xmlparser.cpp index 3942535b1f..8f133feb20 100644 --- a/utils/ifacecheck/src/xmlparser.cpp +++ b/utils/ifacecheck/src/xmlparser.cpp @@ -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; iFindClass(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; iFindClass(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 typedef std::map 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; isecond); + } + } + // 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 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(); } diff --git a/utils/ifacecheck/src/xmlparser.h b/utils/ifacecheck/src/xmlparser.h index b103cb2c39..8f2d2854fa 100644 --- a/utils/ifacecheck/src/xmlparser.h +++ b/utils/ifacecheck/src/xmlparser.h @@ -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);