BIG CHANGES:

- removed fix from the rungccxml.sh.in; not only it was unnecessary
  but it's also better to keep all references to specific wxWidgets
  classes in a single place: the ifacecheck sources;
- added g_bLogEnabled and LogNull class;
- added an HACK_TO_AUTO_CORRECT_ONLY_VIRTUAL_AND_CONST_ATTRIBUTES
  mode for fixing virtualness and constness of interface headers
  in an automated way
- added options to wxMethod::GetAsString to provide an easier way
  to debug ifacecheck comparisons between wxMethods
- fixed wxMethod::FixMethod for single-line prototypes and added
  a boolean return value from it


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55809 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Francesco Montorsi
2008-09-22 21:55:38 +00:00
parent b7e94bd7eb
commit 97f0dbd6f8
4 changed files with 187 additions and 53 deletions

View File

@@ -79,14 +79,5 @@ if [[ $? != 0 ]]; then
exit exit
fi fi
# FIX for IFACECHECK
# ==================
# these fixes are needed to avoid false warnings/errors by ifacecheck
if [[ "@TOOLKIT@" == "GTK" ]]; then
sed -i -e 's/default="wxBITMAP_TYPE_XPM"/default="wxBITMAP_DEFAULT_TYPE"/g' $gccxmloutput
fi
# cleanup # cleanup
rm $allheaders rm $allheaders

View File

@@ -80,7 +80,7 @@ public:
bool Compare(); bool Compare();
int CompareClasses(const wxClass* iface, const wxClassPtrArray& api); int CompareClasses(const wxClass* iface, const wxClassPtrArray& api);
void FixMethod(const wxString& header, const wxMethod* iface, const wxMethod* api); bool FixMethod(const wxString& header, const wxMethod* iface, const wxMethod* api);
void ShowProgress(); void ShowProgress();
void PrintStatistics(long secs); void PrintStatistics(long secs);
@@ -135,12 +135,16 @@ int IfaceCheckApp::OnRun()
// in any case set basic std preprocessor #defines: // in any case set basic std preprocessor #defines:
m_doxyInterface.AddPreprocessorValue("NULL", "0"); m_doxyInterface.AddPreprocessorValue("NULL", "0");
g_bLogEnabled = false;
// parse the two XML files which contain the real and the doxygen interfaces // parse the two XML files which contain the real and the doxygen interfaces
// for wxWidgets API: // for wxWidgets API:
if (!m_gccInterface.Parse(parser.GetParam(0)) || if (!m_gccInterface.Parse(parser.GetParam(0)) ||
!m_doxyInterface.Parse(parser.GetParam(1))) !m_doxyInterface.Parse(parser.GetParam(1)))
return 1; return 1;
g_bLogEnabled = true;
if (parser.Found(DUMP_SWITCH)) if (parser.Found(DUMP_SWITCH))
{ {
LogMessage("Dumping real API to '%s'...", API_DUMP_FILE); LogMessage("Dumping real API to '%s'...", API_DUMP_FILE);
@@ -163,6 +167,7 @@ int IfaceCheckApp::OnRun()
m_strToMatch = m_strToMatch.Mid(1, len-2); m_strToMatch = m_strToMatch.Mid(1, len-2);
} }
ok = Compare(); ok = Compare();
} }
@@ -311,6 +316,7 @@ int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClassPtrArray& a
if (matches == 0) if (matches == 0)
{ {
bool exit = false;
wxMethodPtrArray overloads; wxMethodPtrArray overloads;
// try searching for methods with the same name but with // try searching for methods with the same name but with
@@ -321,8 +327,36 @@ int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClassPtrArray& a
// append "results" array to "overloads" // append "results" array to "overloads"
WX_APPEND_ARRAY(overloads, results); WX_APPEND_ARRAY(overloads, results);
#define HACK_TO_AUTO_CORRECT_ONLY_VIRTUAL_AND_CONST_ATTRIBUTES 1
#if HACK_TO_AUTO_CORRECT_ONLY_VIRTUAL_AND_CONST_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());
// modify interface header
if (FixMethod(iface->GetHeader(), &m, &tmp))
wxLogMessage("Adjusted attributes of '%s' method", m.GetAsString());
exit = true;
break;
}
if (exit)
break;
#endif
} }
#if HACK_TO_AUTO_CORRECT_ONLY_VIRTUAL_AND_CONST_ATTRIBUTES
if (!exit)
{
#endif
if (overloads.GetCount()==0) if (overloads.GetCount()==0)
{ {
/* /*
@@ -349,9 +383,10 @@ int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClassPtrArray& a
" but has different signature:\n", " but has different signature:\n",
m.GetName(), searchedclasses); m.GetName(), searchedclasses);
warning += "\tdoxy header: " + m.GetAsString(); // get a list of the prototypes with _all_ possible attributes:
warning += "\tdoxy header: " + m.GetAsString(true, true, true);
for (unsigned int j=0; j<overloads.GetCount(); j++) for (unsigned int j=0; j<overloads.GetCount(); j++)
warning += "\n\treal header: " + overloads[j]->GetAsString(); warning += "\n\treal header: " + overloads[j]->GetAsString(true, true, true);
wxPrint(warning + "\n"); wxPrint(warning + "\n");
count++; count++;
@@ -378,20 +413,24 @@ int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClassPtrArray& a
} }
count++; count++;
#if HACK_TO_AUTO_CORRECT_ONLY_VIRTUAL_AND_CONST_ATTRIBUTES
}
#endif
} }
} }
return count; return count;
} }
void IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, const wxMethod* api) bool IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, const wxMethod* api)
{ {
wxASSERT(iface && api); wxASSERT(iface && api);
wxTextFile file; wxTextFile file;
if (!file.Open(header)) { if (!file.Open(header)) {
LogError("\tcan't open the '%s' header file.", header); LogError("\tcan't open the '%s' header file.", header);
return; return false;
} }
// GetLocation() returns the line where the last part of the prototype is placed: // GetLocation() returns the line where the last part of the prototype is placed:
@@ -399,38 +438,50 @@ void IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, con
if (end <= 0 || end >= (int)file.GetLineCount()) { if (end <= 0 || end >= (int)file.GetLineCount()) {
LogWarning("\tinvalid location info for method '%s': %d.", LogWarning("\tinvalid location info for method '%s': %d.",
iface->GetAsString(), iface->GetLocation()); iface->GetAsString(), iface->GetLocation());
return; return false;
} }
if (!file.GetLine(end).Contains(";")) { if (!file.GetLine(end).Contains(";")) {
LogWarning("\tinvalid location info for method '%s': %d.", LogWarning("\tinvalid location info for method '%s': %d.",
iface->GetAsString(), iface->GetLocation()); iface->GetAsString(), iface->GetLocation());
return; return false;
} }
// find the start point of this prototype declaration: // is this a one-line prototype declaration?
int start = end-1;
bool founddecl = false; bool founddecl = false;
while (start > 0 && int start;
!file.GetLine(start).Contains(";") && if (file.GetLine(end).Contains(iface->GetName()))
!file.GetLine(start).Contains("*/"))
{ {
start--; // yes, this prototype is all on this line:
start = end;
founddecl = true;
}
else
{
start = end-1;
founddecl |= file.GetLine(start).Contains(iface->GetName()); // find the start point of this prototype declaration:
while (start > 0 &&
!file.GetLine(start).Contains(";") &&
!file.GetLine(start).Contains("*/"))
{
start--;
founddecl |= file.GetLine(start).Contains(iface->GetName());
}
// start-th line contains either the declaration of another prototype
// or the closing tag */ of a doxygen comment; start one line below
start++;
} }
if (start <= 0 || !founddecl) if (start <= 0 || !founddecl)
{ {
LogError("\tcan't find the beginning of the declaration of '%s' method in '%s' header", LogError("\tcan't find the beginning of the declaration of '%s' method in '%s' header looking backwards from line %d",
iface->GetAsString(), header); iface->GetAsString(), header, end);
return; return false;
} }
// start-th line contains either the declaration of another prototype
// or the closing tag */ of a doxygen comment; start one line below
start++;
// remove the old prototype // remove the old prototype
for (int i=start; i<=end; i++) for (int i=start; i<=end; i++)
file.RemoveLine(start); // remove (end-start)-nth times the start-th line file.RemoveLine(start); // remove (end-start)-nth times the start-th line
@@ -500,13 +551,13 @@ void IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, con
// now save the modification // now save the modification
if (!file.Write()) { if (!file.Write()) {
LogError("\tcan't save the '%s' header file.", header); LogError("\tcan't save the '%s' header file.", header);
return; return false;
} }
// how many lines did we add/remove in total? // how many lines did we add/remove in total?
int nOffset = toinsert.GetCount() + deprecationOffset - (end-start+1); int nOffset = toinsert.GetCount() + deprecationOffset - (end-start+1);
if (nOffset == 0) if (nOffset == 0)
return; return false;
if (g_verbose) if (g_verbose)
LogMessage("\tthe final row offset for following methods is %d lines.", nOffset); LogMessage("\tthe final row offset for following methods is %d lines.", nOffset);
@@ -526,6 +577,8 @@ void IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, con
} }
} }
} }
return true;
} }
bool IfaceCheckApp::ParsePreprocessorOutput(const wxString& filename) bool IfaceCheckApp::ParsePreprocessorOutput(const wxString& filename)

View File

@@ -40,6 +40,9 @@ WX_DEFINE_OBJARRAY(wxClassArray)
// defined in ifacecheck.cpp // defined in ifacecheck.cpp
extern bool g_verbose; extern bool g_verbose;
// global variable:
bool g_bLogEnabled = true;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -88,6 +91,12 @@ void wxType::SetTypeFromString(const wxString& t)
// need to be considered as the same type // need to be considered as the same type
if (m_strTypeClean.EndsWith("Base")) if (m_strTypeClean.EndsWith("Base"))
m_strTypeClean = m_strTypeClean.Left(m_strTypeClean.Len()-4); m_strTypeClean = m_strTypeClean.Left(m_strTypeClean.Len()-4);
// ADHOC-FIX:
// doxygen likes to put wxDateTime:: in front of all wxDateTime enums;
// fix this to avoid false positives
m_strTypeClean.Replace("wxDateTime::", "");
m_strTypeClean.Replace("wxStockGDI::", ""); // same story for some other classes
} }
bool wxType::IsOk() const bool wxType::IsOk() const
@@ -110,6 +119,9 @@ bool wxType::operator==(const wxType& m) const
IsReference() == m.IsReference()) IsReference() == m.IsReference())
return true; return true;
if (g_verbose)
LogMessage("Type '%s' does not match type '%s'", m_strType, m.m_strType);
return false; return false;
} }
@@ -134,7 +146,13 @@ void wxArgumentType::SetDefaultValue(const wxString& defval, const wxString& def
else else
m_strDefaultValue.Replace("NULL", "0"); m_strDefaultValue.Replace("NULL", "0");
*/ */
// ADHOC-FIX:
// doxygen likes to put wxDateTime:: in front of all wxDateTime enums;
// fix this to avoid false positives
m_strDefaultValueForCmp.Replace("wxDateTime::", "");
m_strDefaultValueForCmp.Replace("wxStockGDI::", ""); // same story for some other classes
// ADHOC-FIX:
if (m_strDefaultValue.Contains("wxGetTranslation")) if (m_strDefaultValue.Contains("wxGetTranslation"))
m_strDefaultValue = "_(TOFIX)"; // TODO: wxGetTranslation gives problems to gccxml m_strDefaultValue = "_(TOFIX)"; // TODO: wxGetTranslation gives problems to gccxml
} }
@@ -147,6 +165,13 @@ bool wxArgumentType::operator==(const wxArgumentType& m) const
const wxString& def1 = m_strDefaultValueForCmp.IsEmpty() ? m_strDefaultValue : m_strDefaultValueForCmp; const wxString& def1 = m_strDefaultValueForCmp.IsEmpty() ? m_strDefaultValue : m_strDefaultValueForCmp;
const wxString& def2 = m.m_strDefaultValueForCmp.IsEmpty() ? m.m_strDefaultValue : m.m_strDefaultValueForCmp; const wxString& def2 = m.m_strDefaultValueForCmp.IsEmpty() ? m.m_strDefaultValue : m.m_strDefaultValueForCmp;
// ADHOC-FIX:
// default values for style attributes of wxWindow-derived classes in gccxml appear as raw
// numbers; avoid false positives in this case!
if (m_strArgName == m.m_strArgName && m_strArgName == "style" &&
(def1.IsNumber() || def2.IsNumber()))
return true;
if (def1 != def2) if (def1 != def2)
{ {
// maybe the default values are numbers. // maybe the default values are numbers.
@@ -160,6 +185,9 @@ bool wxArgumentType::operator==(const wxArgumentType& m) const
return true; // the default values match return true; // the default values match
} }
if (g_verbose)
LogMessage("Argument type '%s = %s' has different default value from '%s = %s'",
m_strType, def1, m.m_strType, def2);
return false; return false;
} }
@@ -222,20 +250,20 @@ bool wxMethod::IsOk() const
return true; return true;
} }
bool wxMethod::operator==(const wxMethod& m) const bool wxMethod::MatchesExceptForAttributes(const wxMethod& m) const
{ {
if (GetReturnType() != m.GetReturnType() || if (GetReturnType() != m.GetReturnType() ||
GetName() != m.GetName() || GetName() != m.GetName())
IsConst() != m.IsConst() ||
IsStatic() != m.IsStatic() ||
IsVirtual() != m.IsVirtual() ||
IsPureVirtual() != m.IsPureVirtual() ||
IsDeprecated() != m.IsDeprecated())
return false; return false;
if (m_args.GetCount()!=m.m_args.GetCount()) if (m_args.GetCount()!=m.m_args.GetCount()) {
if (g_verbose)
LogMessage("Method '%s' has %d arguments while '%s' has %d arguments",
m_strName, m_args.GetCount(), m_strName, m.m_args.GetCount());
return false; return false;
}
// compare argument types
for (unsigned int i=0; i<m_args.GetCount(); i++) for (unsigned int i=0; i<m_args.GetCount(); i++)
if (m_args[i] != m.m_args[i]) if (m_args[i] != m.m_args[i])
return false; return false;
@@ -243,12 +271,31 @@ bool wxMethod::operator==(const wxMethod& m) const
return true; return true;
} }
wxString wxMethod::GetAsString(bool bWithArgumentNames) const bool wxMethod::operator==(const wxMethod& m) const
{
// check attributes
if (IsConst() != m.IsConst() ||
IsStatic() != m.IsStatic() ||
IsVirtual() != m.IsVirtual() ||
IsPureVirtual() != m.IsPureVirtual() ||
IsDeprecated() != m.IsDeprecated())
return false;
// check everything else
return MatchesExceptForAttributes(m);
}
wxString wxMethod::GetAsString(bool bWithArgumentNames, bool bClean, bool bDeprecated) const
{ {
wxString ret; wxString ret;
if (m_retType!=wxEmptyType) if (m_retType!=wxEmptyType)
ret += m_retType.GetAsString() + " "; {
if (bClean)
ret += m_retType.GetAsCleanString() + " ";
else
ret += m_retType.GetAsString() + " ";
}
//else; this is a ctor or dtor //else; this is a ctor or dtor
ret += m_strName + "("; ret += m_strName + "(";
@@ -261,7 +308,8 @@ wxString wxMethod::GetAsString(bool bWithArgumentNames) const
if (bWithArgumentNames && !name.IsEmpty()) if (bWithArgumentNames && !name.IsEmpty())
ret += " " + name; ret += " " + name;
const wxString& def = m_args[i].GetDefaultValue(); const wxString& def = bClean ?
m_args[i].GetDefaultCleanValue() : m_args[i].GetDefaultValue();
if (!def.IsEmpty()) if (!def.IsEmpty())
ret += " = " + def; ret += " = " + def;
@@ -280,11 +328,9 @@ wxString wxMethod::GetAsString(bool bWithArgumentNames) const
if (m_bVirtual || m_bPureVirtual) if (m_bVirtual || m_bPureVirtual)
ret = "virtual " + ret; ret = "virtual " + ret;
if (m_bPureVirtual) if (m_bPureVirtual)
ret = ret + " = 0"; ret += " = 0";
if (m_bDeprecated && bDeprecated)
// in doxygen headers we don't need wxDEPRECATED: ret += " [deprecated]";
//if (m_bDeprecated)
// ret = "wxDEPRECATED( " + ret + " )";
return ret; return ret;
} }
@@ -967,7 +1013,9 @@ bool wxXmlGccInterface::ParseMethod(const wxXmlNode *p,
return false; return false;
} }
argtypes.Add(wxArgumentType(idx->second, arg->GetAttribute("default"))); argtypes.Add(wxArgumentType(idx->second,
arg->GetAttribute("default"),
arg->GetAttribute("name")));
} }
arg = arg->GetNext(); arg = arg->GetNext();

View File

@@ -17,12 +17,38 @@
#include <wx/xml/xml.h> #include <wx/xml/xml.h>
#include <wx/platinfo.h> #include <wx/platinfo.h>
/*
IMPORTANT
=========
Any fix aimed to reduce "false positives" which involves
references to a specific wxWidgets class is marked in
ifacecheck sources with the string:
// ADHOC-FIX:
*/
// helper macros // helper macros
#define LogMessage(fmt, ...) { wxPrintf(fmt "\n", __VA_ARGS__); fflush(stdout); } #define LogMessage(fmt, ...) { if (g_bLogEnabled) { wxPrintf(fmt "\n", __VA_ARGS__); fflush(stdout); }}
#define LogWarning(fmt, ...) { wxPrintf(fmt "\n", __VA_ARGS__); fflush(stdout); } #define LogWarning(fmt, ...) { if (g_bLogEnabled) { wxPrintf(fmt "\n", __VA_ARGS__); fflush(stdout); }}
#define LogError(fmt, ...) { wxPrintf("ERROR: " fmt "\n", __VA_ARGS__); fflush(stdout); } #define LogError(fmt, ...) { if (g_bLogEnabled) { wxPrintf("ERROR: " fmt "\n", __VA_ARGS__); fflush(stdout); }}
#define wxPrint(str) { wxPrintf(str); fflush(stdout); } #define wxPrint(str) { wxPrintf(str); fflush(stdout); }
// enable/disable logging
extern bool g_bLogEnabled;
class LogNull
{
public:
LogNull() { g_bLogEnabled = false; }
~LogNull() { g_bLogEnabled = true; }
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Represents a type with or without const/static/ qualifier // Represents a type with or without const/static/ qualifier
@@ -38,6 +64,8 @@ public:
void SetTypeFromString(const wxString& t); void SetTypeFromString(const wxString& t);
wxString GetAsString() const wxString GetAsString() const
{ return m_strType; } { return m_strType; }
wxString GetAsCleanString() const
{ return m_strTypeClean; }
bool IsConst() const bool IsConst() const
{ return m_strType.Contains("const"); } { return m_strType.Contains("const"); }
@@ -83,6 +111,8 @@ public:
void SetDefaultValue(const wxString& defval, const wxString& defvalForCmp = wxEmptyString); void SetDefaultValue(const wxString& defval, const wxString& defvalForCmp = wxEmptyString);
wxString GetDefaultValue() const wxString GetDefaultValue() const
{ return m_strDefaultValue; } { return m_strDefaultValue; }
wxString GetDefaultCleanValue() const
{ return m_strDefaultValueForCmp.IsEmpty() ? m_strDefaultValue : m_strDefaultValueForCmp; }
bool HasDefaultValue() const bool HasDefaultValue() const
{ return !m_strDefaultValue.IsEmpty(); } { return !m_strDefaultValue.IsEmpty(); }
@@ -127,7 +157,12 @@ public:
public: // getters public: // getters
wxString GetAsString(bool bWithArgumentNames = true) const; // bWithArgumentNames = output argument names?
// bClean = output type names or type _clean_ names (see wxType::GetAsCleanString)
// bDeprecated = output [deprecated] next to deprecated methods?
wxString GetAsString(bool bWithArgumentNames = true,
bool bClean = false,
bool bDeprecated = false) const;
// parser of the prototype: // parser of the prototype:
// all these functions return strings with spaces stripped // all these functions return strings with spaces stripped
@@ -193,6 +228,13 @@ public: // misc
bool operator!=(const wxMethod& m) const bool operator!=(const wxMethod& m) const
{ return !(*this == m); } { return !(*this == m); }
// this function works like operator== but tests everything:
// - method name
// - return type
// - argument types
// except for the method attributes (const,static,virtual,pureVirtual,deprecated)
bool MatchesExceptForAttributes(const wxMethod& m) const;
void Dump(wxTextOutputStream& stream) const; void Dump(wxTextOutputStream& stream) const;
protected: protected: