]> git.saurik.com Git - wxWidgets.git/commitdiff
add the ability to parse the gccxml preprocessor output in order to reduce the number...
authorFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Thu, 27 Mar 2008 19:15:00 +0000 (19:15 +0000)
committerFrancesco Montorsi <f18m_cpp217828@yahoo.it>
Thu, 27 Mar 2008 19:15:00 +0000 (19:15 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52861 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

utils/ifacecheck/rungccxml.sh.in
utils/ifacecheck/src/ifacecheck.cpp
utils/ifacecheck/src/xmlparser.cpp
utils/ifacecheck/src/xmlparser.h

index a5a34265f25ce20606a7404822b81c7431ed4559..fcd58240cc1367fc35e16b1dabb1a10a40b8dd33 100755 (executable)
@@ -11,8 +11,9 @@
 ############
 
 
-gccxmloutput="wxapi.xml"        # where do we put the gccXML output:
-allheaders="/tmp/wx-all.h"      # headers which includes all wx public headers
+gccxmloutput="wxapi.xml"             # the file where we store the gccXML output
+preprocoutput="wxapi-preproc.txt"    # the file where we store the preprocessor's #define values
+allheaders="/tmp/wx-all.h"           # the header which includes all wx public headers (autogenerated)
 
 # the list of all wxWidgets public headers
 listcmd="ls wx/*.h wx/aui/*.h wx/html/*.h wx/protocol/*.h wx/richtext/*.h wx/stc/*.h wx/xml/*.h wx/xrc/*.h"
@@ -52,14 +53,22 @@ done
 flags="@CXXFLAGS@"
 
 # NOTE: it's important to define __WXDEBUG__ because some functions of wx
-#       are declared (and thus parsed by gcc) only if that symbol is defined;
-#       so we remove __WXDEBUG__ symbol from $flags, in case it's defined:
+#       are declared (and thus parsed by gcc) only if that symbol is defined.
+#       So we remove it from $flags (in case it's defined) and then readd it.
 flags=`echo "$flags" | sed -e 's/-pthread//g' | sed -e 's/__WXDEBUG__//g'`
 
+# append some other flags:
+flags="-I . -I @top_srcdir@/include $flags -D__WXDEBUG__ -D__WX@TOOLKIT@__ -DWXBUILDING $allheaders"
+
 # run gccxml with the same flag used for the real compilation of wx sources:
 echo "Running gccxml on the $allheaders file..."
 if [[ -f "$gccxmloutput" ]]; then rm $gccxmloutput; fi
-gccxml -I . -I @top_srcdir@/include $flags -D__WX@TOOLKIT@__ -DWXBUILDING $allheaders -fxml=$gccxmloutput
+gccxml $flags -fxml=$gccxmloutput
+
+# now get the list of the #defined values for wx headers, so that the result
+# can be passed to ifacecheck to aid the comparison
+echo "Running gccxml's preprocessor on the $allheaders file..."
+gccxml -E -dM $flags >$preprocoutput
 
 # cleanup
 rm $allheaders
index 033e29e5a175bfe9b61fbbd92659c17e4537b12b..d2c63869e60753605e433e0b9e90d647ed1ab060 100644 (file)
@@ -35,18 +35,23 @@ bool g_verbose = false;
 // IfaceCheckApp
 // ----------------------------------------------------------------------------
 
-#define API_DUMP_FILE           "dump.api.txt"
-#define INTERFACE_DUMP_FILE     "dump.interface.txt"
+#define API_DUMP_FILE               "dump.api.txt"
+#define INTERFACE_DUMP_FILE         "dump.interface.txt"
 
-#define PROCESS_ONLY_SWITCH     "p"
-#define MODIFY_SWITCH           "m"
-#define DUMP_SWITCH             "d"
-#define HELP_SWITCH             "h"
-#define VERBOSE_SWITCH          "v"
+#define PROCESS_ONLY_OPTION         "p"
+#define USE_PREPROCESSOR_OPTION     "u"
+
+#define MODIFY_SWITCH               "m"
+#define DUMP_SWITCH                 "d"
+#define HELP_SWITCH                 "h"
+#define VERBOSE_SWITCH              "v"
 
 static const wxCmdLineEntryDesc g_cmdLineDesc[] =
 {
-    { wxCMD_LINE_OPTION, PROCESS_ONLY_SWITCH, "process-only",
+    { wxCMD_LINE_OPTION, USE_PREPROCESSOR_OPTION, "use-preproc",
+        "uses the preprocessor output to increase the checker accuracy",
+        wxCMD_LINE_VAL_STRING, wxCMD_LINE_NEEDS_SEPARATOR },
+    { wxCMD_LINE_OPTION, PROCESS_ONLY_OPTION, "process-only",
         "processes only header files matching the given wildcard",
         wxCMD_LINE_VAL_STRING, wxCMD_LINE_NEEDS_SEPARATOR },
     { wxCMD_LINE_SWITCH, MODIFY_SWITCH, "modify",
@@ -71,6 +76,8 @@ public:
     virtual bool OnInit() { m_modify=false; return true; }
     virtual int OnRun();
 
+    bool ParsePreprocessorOutput(const wxString& filename);
+
     bool Compare();
     int CompareClasses(const wxClass* iface, const wxClassPtrArray& api);
     void FixMethod(const wxString& header, const wxMethod* iface, const wxMethod* api);
@@ -92,7 +99,7 @@ protected:
     // was the MODIFY_SWITCH passed?
     bool m_modify;
 
-    // if non-empty, then PROCESS_ONLY_SWITCH was passed and this is the
+    // if non-empty, then PROCESS_ONLY_OPTION was passed and this is the
     // wildcard expression to match
     wxString m_strToMatch;
 };
@@ -103,19 +110,33 @@ int IfaceCheckApp::OnRun()
 {
     long startTime = wxGetLocalTime();      // for timing purpose
 
-    // parse the command line...
     wxCmdLineParser parser(g_cmdLineDesc, argc, argv);
+    parser.SetLogo(
+        wxString::Format("wxWidgets Interface checker utility (built %s against %s)",
+                         __DATE__, wxVERSION_STRING));
+
+    // parse the command line...
     bool ok = true;
+    wxString preprocFile;
     switch (parser.Parse())
     {
-        case -1:
-            // HELP_SWITCH was passed
-            return 0;
-
         case 0:
             if (parser.Found(VERBOSE_SWITCH))
                 g_verbose = true;
 
+            // IMPORTANT: parsing #define values must be done _before_ actually
+            //            parsing the GCC/doxygen XML files
+            if (parser.Found(USE_PREPROCESSOR_OPTION, &preprocFile))
+            {
+                if (!ParsePreprocessorOutput(preprocFile))
+                    return 1;
+            }
+
+            // in any case set basic std preprocessor #defines:
+            m_interface.AddPreprocessorValue("NULL", "0");
+
+            // parse the two XML files which contain the real and the doxygen interfaces
+            // for wxWidgets API:
             if (!m_api.Parse(parser.GetParam(0)) ||
                 !m_interface.Parse(parser.GetParam(1)))
                 return 1;
@@ -133,7 +154,7 @@ int IfaceCheckApp::OnRun()
                 if (parser.Found(MODIFY_SWITCH))
                     m_modify = true;
 
-                if (parser.Found(PROCESS_ONLY_SWITCH, &m_strToMatch))
+                if (parser.Found(PROCESS_ONLY_OPTION, &m_strToMatch))
                 {
                     size_t len = m_strToMatch.Len();
                     if (m_strToMatch.StartsWith("\"") &&
@@ -147,6 +168,20 @@ int IfaceCheckApp::OnRun()
 
             PrintStatistics(wxGetLocalTime() - startTime);
             return ok ? 0 : 1;
+
+        default:
+            wxPrintf("\nThis utility checks that the interface XML files created by Doxygen are in\n");
+            wxPrintf("synch with the real headers (whose contents are extracted by the gcc XML file).\n\n");
+            wxPrintf("The 'gccXML' parameter should be the wxapi.xml file created by the 'rungccxml.sh'\n");
+            wxPrintf("script which resides in 'utils/ifacecheck'.\n");
+            wxPrintf("The 'doxygenXML' parameter should be the index.xml file created by Doxygen\n");
+            wxPrintf("for the wxWidgets 'interface' folder.\n\n");
+            wxPrintf("Since the gcc XML file does not contain info about #defines, if you use\n");
+            wxPrintf("the -%s option, you'll get a smaller number of false warnings.\n",
+                     USE_PREPROCESSOR_OPTION);
+
+            // HELP_SWITCH was passed or a syntax error occurred
+            return 0;
     }
 
     return 1;
@@ -462,6 +497,48 @@ void IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, con
     }
 }
 
+bool IfaceCheckApp::ParsePreprocessorOutput(const wxString& filename)
+{
+    wxTextFile tf;
+    if (!tf.Open(filename)) {
+        LogError("can't open the '%s' preprocessor output file.", filename);
+        return false;
+    }
+
+    size_t useful = 0;
+    for (unsigned int i=0; i < tf.GetLineCount(); i++)
+    {
+        const wxString& line = tf.GetLine(i);
+        wxString defnameval = line.Mid(8);     // what follows the "#define " string
+
+        // the format of this line should be:
+        //    #define DEFNAME DEFVALUE
+        if (!line.StartsWith("#define ") || !defnameval.Contains(" ")) {
+            LogError("unexpected content in '%s' at line %d.", filename, i);
+            return false;
+        }
+
+        // get DEFNAME
+        wxString defname = defnameval.BeforeFirst(' ');
+        if (defname.Contains("("))
+            continue;       // this is a macro, skip it!
+
+        // get DEFVAL
+        wxString defval = defnameval.AfterFirst(' ').Strip(wxString::both);
+        if (defval.StartsWith("(") && defval.EndsWith(")"))
+            defval = defval.Mid(1, defval.Len()-2);
+
+        // store this pair in the doxygen interface, where it can be useful
+        m_interface.AddPreprocessorValue(defname, defval);
+        useful++;
+    }
+
+    LogMessage("Parsed %d preprocessor #defines from '%s' which will be used later...",
+               useful, filename);
+
+    return true;
+}
+
 void IfaceCheckApp::PrintStatistics(long secs)
 {
     LogMessage("wx real headers contains declaration of %d classes (%d methods)",
index d694d9a87cf413172e1e8f3b56e8101f7a4301ac..69d5684f1d891984e0d7c381b21db608f8eb178f 100644 (file)
@@ -115,10 +115,11 @@ bool wxType::operator==(const wxType& m) const
 // wxArgumentType
 // ----------------------------------------------------------------------------
 
-void wxArgumentType::SetDefaultValue(const wxString& defval)
+void wxArgumentType::SetDefaultValue(const wxString& defval, const wxString& defvalForCmp)
 {
     m_strDefaultValue=defval.Strip(wxString::both);
-
+    m_strDefaultValueForCmp=defvalForCmp.Strip(wxString::both);
+/*
     // 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:
@@ -128,7 +129,7 @@ void wxArgumentType::SetDefaultValue(const wxString& defval)
         m_strDefaultValue.Replace("0", "NULL");
     else
         m_strDefaultValue.Replace("NULL", "0");
-
+*/
 
     if (m_strDefaultValue.Contains("wxGetTranslation"))
         m_strDefaultValue = "_(TOFIX)";     // TODO: wxGetTranslation gives problems to gccxml
@@ -139,7 +140,10 @@ bool wxArgumentType::operator==(const wxArgumentType& m) const
     if ((const wxType&)(*this) != (const wxType&)m)
         return false;
 
-    if (m_strDefaultValue != m.m_strDefaultValue)
+    const wxString& def1 = m_strDefaultValueForCmp.IsEmpty() ? m_strDefaultValue : m_strDefaultValueForCmp;
+    const wxString& def2 = m.m_strDefaultValueForCmp.IsEmpty() ? m.m_strDefaultValue : m.m_strDefaultValueForCmp;
+
+    if (def1 != def2)
         return false;
 
     // we deliberately avoid checks on the argument name
@@ -170,7 +174,7 @@ bool wxMethod::IsOk() const
         return false;
     }
 
-    wxASSERT((m_bVirtual && m_bPureVirtual) || !m_bVirtual);
+    wxASSERT(!m_bPureVirtual || (m_bPureVirtual && m_bVirtual));
 
     for (unsigned int i=0; i<m_args.GetCount(); i++)
         if (!m_args[i].IsOk()) {
@@ -403,11 +407,11 @@ void wxXmlInterface::Dump(const wxString& filename)
 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;
 }
@@ -1163,7 +1167,7 @@ bool wxXmlDoxygenInterface::ParseMethod(const wxXmlNode* p, wxMethod& m, wxStrin
                 else if (n->GetName() == "declname")
                     namestr = GetTextFromChildren(n);
                 else if (n->GetName() == "defval")
-                    defstr = GetTextFromChildren(n);
+                    defstr = GetTextFromChildren(n).Strip(wxString::both);
                 else if (n->GetName() == "array")
                     arrstr = GetTextFromChildren(n);
 
@@ -1175,7 +1179,15 @@ bool wxXmlDoxygenInterface::ParseMethod(const wxXmlNode* p, wxMethod& m, wxStrin
                 return false;
             }
 
-            args.Add(wxArgumentType(typestr + arrstr, defstr, namestr));
+            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")
         {
index a002f4244d74b37c847de5c375712a3357a154b5..6e1de99a42fede5c8c12a40ff9f090bb2eae5c37 100644 (file)
@@ -80,7 +80,7 @@ public:
     wxString GetArgumentName() const
         { return m_strArgName; }
 
-    void SetDefaultValue(const wxString& defval);
+    void SetDefaultValue(const wxString& defval, const wxString& defvalForCmp = wxEmptyString);
     wxString GetDefaultValue() const
         { return m_strDefaultValue; }
 
@@ -93,6 +93,11 @@ public:
 
 protected:
     wxString m_strDefaultValue;
+
+    // this string may differ from m_strDefaultValue if there were
+    // preprocessor substitutions; can be wxEmptyString.
+    wxString m_strDefaultValueForCmp;
+
     wxString m_strArgName;      // this one only makes sense when this wxType is
                                 // used as argument type (and not as return type)
                                 // and can be empty.
@@ -312,6 +317,8 @@ protected:
 WX_DECLARE_HASH_MAP( unsigned long, wxString,
                      wxIntegerHash, wxIntegerEqual,
                      wxTypeIdHashMap );
+
+WX_DECLARE_STRING_HASH_MAP( wxString, wxStringHashMap );
 #else
 #include <map>
 typedef std::basic_string<char> stlString;
@@ -328,14 +335,6 @@ class wxXmlGccInterface : public wxXmlInterface
 public:
     wxXmlGccInterface() {}
 
-    // !!SPEEDUP-TODO!!
-    // Using wxXmlDocument::Load as is, all the types contained in the
-    // the entire gccXML file are stored in memory while parsing;
-    // however we are only interested to wx's own structs/classes/funcs/etc
-    // so that we could use the file IDs to avoid loading stuff which does
-    // not belong to wx. See the very end of the gccXML file: it contains
-    // a set of <File> nodes referenced by all nodes above.
-
     bool Parse(const wxString& filename);
     bool ParseMethod(const wxXmlNode *p,
                      const wxTypeIdHashMap& types,
@@ -363,6 +362,14 @@ public:
     bool Parse(const wxString& filename);
     bool ParseCompoundDefinition(const wxString& filename);
     bool ParseMethod(const wxXmlNode*, wxMethod&, wxString& header);
+
+    // this class can take advantage of the preprocessor output to give
+    // a minor number of false positive warnings in the final comparison
+    void AddPreprocessorValue(const wxString& name, const wxString& val)
+        { m_preproc[name]=val; }
+
+protected:
+    wxStringHashMap m_preproc;
 };