]> git.saurik.com Git - wxWidgets.git/commitdiff
BIG CHANGE: added parsing of base classes; now CompareClasses() is much smarter since...
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Mon, 29 Sep 2008 16:11:23 +0000 (16:11 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Mon, 29 Sep 2008 16:11:23 +0000 (16:11 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55948 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

utils/ifacecheck/src/ifacecheck.cpp
utils/ifacecheck/src/xmlparser.cpp
utils/ifacecheck/src/xmlparser.h

index 5e03123d2581574a6cc537aa470ab3fd350beff0..f7df0abaa890d816219e54c239525fc87b984ec4 100644 (file)
@@ -79,7 +79,7 @@ public:
     bool ParsePreprocessorOutput(const wxString& filename);
 
     bool Compare();
     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();
     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;
 {
     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)...",
     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();
 
 
         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.
         // 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 {
 
 
         } else {
 
@@ -271,18 +271,12 @@ bool IfaceCheckApp::Compare()
     return true;
 }
 
     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;
 
     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();
 
     // 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);
     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
 
         // 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
         }
 
         // 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;
         {
             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
 
 #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;
                     break;
-#endif
-            }
+                }
 
 
-#if HACK_TO_AUTO_CORRECT_ONLY_METHOD_ATTRIBUTES
             if (!exit)
             {
 #endif
 
             if (overloads.GetCount()==0)
             {
             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
                 // 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",
                 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",
                 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);
 
                 // get a list of the prototypes with _all_ possible attributes:
                 warning += "\tdoxy header: " + m.GetAsString(true, true, true, true);
index 3942535b1f6e1734ba4d0d2232a57f79bfc776e7..8f133feb20852a07b7ced80191bd32b1b639fe5e 100644 (file)
@@ -147,7 +147,11 @@ void wxArgumentType::SetDefaultValue(const wxString& defval, const wxString& def
     if (m_strDefaultValueForCmp == "0u")
         m_strDefaultValueForCmp = "0";
 
     if (m_strDefaultValueForCmp == "0u")
         m_strDefaultValueForCmp = "0";
 
+    m_strDefaultValue.Replace("0x000000001", "1");
+    m_strDefaultValueForCmp.Replace("0x000000001", "1");
+
     // fix for unicode strings:
     // fix for unicode strings:
+    m_strDefaultValue.Replace("\\000\\000\\000", "");
     m_strDefaultValueForCmp.Replace("\\000\\000\\000", "");
 
     if (m_strDefaultValueForCmp.StartsWith("wxT(") &&
     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;
 }
 
     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::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
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // wxXmlInterface
 // ----------------------------------------------------------------------------
@@ -554,6 +621,10 @@ wxClassPtrArray wxXmlInterface::FindClassesDefinedIn(const wxString& headerfile)
 #define ATTRIB_POINTER      4
 #define ATTRIB_ARRAY        8
 
 #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
 #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 );
 WX_DECLARE_HASH_MAP( unsigned long, wxClass*,
                      wxIntegerHash, wxIntegerEqual,
                      wxClassMemberIdHashMap );
+
 #else
 #include <map>
 typedef std::map<unsigned long, toResolveTypeItem> wxToResolveTypeHashMap;
 #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")));
 
                 // 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())
                 {
                 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:
                 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;
                         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);
     }
 
             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)
     // 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)
 {
 
 bool wxXmlDoxygenInterface::ParseCompoundDefinition(const wxString& filename)
 {
+    wxClassMemberIdHashMap parents;
     wxXmlDocument doc;
     wxXmlNode *child;
     int nodes = 0;
     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));
                 }
                     // 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();
             }
 
                 subchild = subchild->GetNext();
             }
index b103cb2c39db5cf47c6e0aa27c24e11ea1501076..8f2d2854fa49b309df64fc52f04d0b2270c50011 100644 (file)
@@ -288,6 +288,14 @@ WX_DECLARE_OBJARRAY(wxMethod, wxMethodArray);
 WX_DEFINE_ARRAY(const wxMethod*, wxMethodPtrArray);
 
 
 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.
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // Represents a class of the wx API/interface.
 // ----------------------------------------------------------------------------
@@ -307,7 +315,8 @@ public:     // setters
         { m_strName=name; }
     void SetAvailability(int nAvail)
         { m_nAvailability=nAvail; }
         { m_strName=name; }
     void SetAvailability(int nAvail)
         { m_nAvailability=nAvail; }
-
+    void SetParent(unsigned int k, const wxString& name)
+        { m_parents[k]=name; }
 
 public:     // getters
 
 
 public:     // getters
 
@@ -333,18 +342,37 @@ public:     // getters
     int GetAvailability() const
         { return m_nAvailability; }
 
     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); }
 
 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;
 
     // 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
     // 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;
 
     // dumps all methods to the given output stream
     void Dump(wxTextOutputStream& stream) const;
@@ -357,12 +385,17 @@ protected:
     wxString m_strHeader;
     wxMethodArray m_methods;
 
     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);
     // see the wxMethod::m_nAvailability field for more info
     int m_nAvailability;
 };
 
 WX_DECLARE_OBJARRAY(wxClass, wxClassArray);
-WX_DEFINE_ARRAY(const wxClass*, wxClassPtrArray);