add the ability to parse the gccxml preprocessor output in order to reduce the number of false positives; fix wrong wxASSERT in wxMethod::IsOk; provide more help when called with --help

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@52861 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Francesco Montorsi
2008-03-27 19:15:00 +00:00
parent 1512f0f7d8
commit 5570107a9d
4 changed files with 143 additions and 38 deletions

View 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)",