wxCMD_LINE_DESC_END
};
+class IfaceCheckLog : public wxLog
+{
+public:
+ IfaceCheckLog() {}
+
+ void DoLog(wxLogLevel level, const wxString& msg, time_t stamp)
+ {
+ wxPrintf(msg);
+ wxPrintf("\n");
+ Flush();
+ }
+};
+
class IfaceCheckApp : public wxAppConsole
{
public:
bool FixMethod(const wxString& header, const wxMethod* iface, const wxMethod* api);
bool StringContainsMethodName(const wxString& str, const wxMethod* m);
- void ShowProgress();
void PrintStatistics(long secs);
bool IsToProcess(const wxString& headername) const
wxString::Format("wxWidgets Interface checker utility (built %s against %s)",
__DATE__, wxVERSION_STRING));
+ // make the output more readable:
+ wxLog::SetActiveTarget(new IfaceCheckLog);
+ wxLog::DisableTimestamp();
+
// parse the command line...
bool ok = true;
wxString preprocFile;
!m_doxyInterface.Parse(parser.GetParam(1)))
return 1;
- g_bLogEnabled = true;
+// g_bLogEnabled = true;
if (parser.Found(DUMP_SWITCH))
{
- LogMessage("Dumping real API to '%s'...", API_DUMP_FILE);
+ wxLogMessage("Dumping real API to '%s'...", API_DUMP_FILE);
m_gccInterface.Dump(API_DUMP_FILE);
- LogMessage("Dumping interface API to '%s'...", INTERFACE_DUMP_FILE);
+ wxLogMessage("Dumping interface API to '%s'...", INTERFACE_DUMP_FILE);
m_doxyInterface.Dump(INTERFACE_DUMP_FILE);
}
else
}
}
-void IfaceCheckApp::ShowProgress()
-{
- wxPrint(".");
- //fflush(stdout);
-}
-
bool IfaceCheckApp::Compare()
{
const wxClassArray& interfaces = m_doxyInterface.GetClasses();
const wxClass* c;
int mcount = 0, ccount = 0;
- LogMessage("Comparing the interface API to the real API (%d classes to compare)...",
- interfaces.GetCount());
+ wxLogMessage("Comparing the interface API to the real API (%d classes to compare)...",
+ interfaces.GetCount());
if (!m_strToMatch.IsEmpty())
- LogMessage("Processing only header files matching '%s' expression.", m_strToMatch);
+ wxLogMessage("Processing only header files matching '%s' expression.", m_strToMatch);
for (unsigned int i=0; i<interfaces.GetCount(); i++)
{
(interfaces[i].GetAvailability() & m_gccInterface.GetInterfacePort()) == 0) {
if (g_verbose)
- LogMessage("skipping class '%s' since it's not available for the %s port.",
+ wxLogMessage("skipping class '%s' since it's not available for the %s port.",
interfaces[i].GetName(), m_gccInterface.GetInterfacePortName());
continue; // skip this method
} else {
- LogMessage("%s: couldn't find the real interface for the '%s' class",
+ wxLogMessage("%s: couldn't find the real interface for the '%s' class",
header, cname);
ccount++;
}
}
- LogMessage("%d on a total of %d methods (%.1f%%) of the interface headers do not exist in the real headers",
+ wxLogMessage("%d on a total of %d methods (%.1f%%) of the interface headers do not exist in the real headers",
mcount, m_doxyInterface.GetMethodCount(), (float)(100.0 * mcount/m_doxyInterface.GetMethodCount()));
- LogMessage("%d on a total of %d classes (%.1f%%) of the interface headers do not exist in the real headers",
+ wxLogMessage("%d on a total of %d classes (%.1f%%) of the interface headers do not exist in the real headers",
ccount, m_doxyInterface.GetClassesCount(), (float)(100.0 * ccount/m_doxyInterface.GetClassesCount()));
return true;
(m.GetAvailability() & m_gccInterface.GetInterfacePort()) == 0) {
if (g_verbose)
- LogMessage("skipping method '%s' since it's not available for the %s port.",
+ wxLogMessage("skipping method '%s' since it's not available for the %s port.",
m.GetAsString(), m_gccInterface.GetInterfacePortName());
continue; // skip this method
// modify interface header
if (FixMethod(iface->GetHeader(), &m, &tmp))
- LogMessage("Adjusted attributes of '%s' method", m.GetAsString());
+ wxLogMessage("Adjusted attributes of '%s' method", m.GetAsString());
proceed = false;
break;
{
if (overloads.GetCount()==0)
{
- LogMessage("%s: real '%s' class and their parents have no method '%s'",
+ wxLogMessage("%s: real '%s' class and their parents have no method '%s'",
header, api->GetName(), m.GetAsString());
// we've found no overloads
}
for (unsigned int j=0; j<overloads.GetCount(); j++)
warning += "\n\treal header: " + overloads[j]->GetAsString(true, true, true, true);
- wxPrint(warning + "\n");
+ wxLogWarning(warning);
count++;
if (overloads.GetCount()>1)
// TODO: decide which of these overloads is the most "similar" to m
// and eventually modify it
if (m_modify)
- wxPrint("\tmanual fix is required\n");
+ wxLogWarning("\tmanual fix is required");
}
else
{
if (m_modify || m.IsCtor())
{
- wxPrint("\tfixing it...\n");
+ wxLogWarning("\tfixing it...");
// try to modify it!
FixMethod(iface->GetHeader(), &m, overloads[0]);
wxTextFile file;
if (!file.Open(header)) {
- LogError("\tcan't open the '%s' header file.", header);
+ wxLogError("\tcan't open the '%s' header file.", header);
return false;
}
// i.e. the line containing the semicolon at the end of the declaration.
int end = iface->GetLocation()-1;
if (end <= 0 || end >= (int)file.GetLineCount()) {
- LogWarning("\tinvalid location info for method '%s': %d.",
+ wxLogWarning("\tinvalid location info for method '%s': %d.",
iface->GetAsString(), iface->GetLocation());
return false;
}
if (!file.GetLine(end).Contains(";")) {
- LogWarning("\tinvalid location info for method '%s': %d.",
+ wxLogWarning("\tinvalid location info for method '%s': %d.",
iface->GetAsString(), iface->GetLocation());
return false;
}
if (start <= 0 || !founddecl)
{
- LogError("\tcan't find the beginning of the declaration of '%s' method in '%s' header looking backwards from line %d; I arrived at %d and gave up",
+ wxLogError("\tcan't find the beginning of the declaration of '%s' method in '%s' header looking backwards from line %d; I arrived at %d and gave up",
iface->GetAsString(), header, end+1 /* zero-based => 1-based */, start);
return false;
}
// now save the modification
if (!file.Write()) {
- LogError("\tcan't save the '%s' header file.", header);
+ wxLogError("\tcan't save the '%s' header file.", header);
return false;
}
return false;
if (g_verbose)
- LogMessage("\tthe final row offset for following methods is %d lines.", nOffset);
+ wxLogMessage("\tthe final row offset for following methods is %d lines.", nOffset);
// update the other method's locations for those methods which belong to the modified header
// and are placed _below_ the modified method
{
wxTextFile tf;
if (!tf.Open(filename)) {
- LogError("can't open the '%s' preprocessor output file.", filename);
+ wxLogError("can't open the '%s' preprocessor output file.", filename);
return false;
}
// the format of this line should be:
// #define DEFNAME DEFVALUE
if (!line.StartsWith("#define ")) {
- LogError("unexpected content in '%s' at line %d.", filename, i+1);
+ wxLogError("unexpected content in '%s' at line %d.", filename, i+1);
return false;
}
}
}
- LogMessage("Parsed %d preprocessor #defines from '%s' which will be used later...",
+ wxLogMessage("Parsed %d preprocessor #defines from '%s' which will be used later...",
useful, filename);
return true;
// these stats, for what regards the gcc XML, are all referred to the wxWidgets
// classes only!
- LogMessage("wx real headers contains declaration of %d classes (%d methods)",
+ wxLogMessage("wx real headers contains declaration of %d classes (%d methods)",
m_gccInterface.GetClassesCount(), m_gccInterface.GetMethodCount());
- LogMessage("wx interface headers contains declaration of %d classes (%d methods)",
+ wxLogMessage("wx interface headers contains declaration of %d classes (%d methods)",
m_doxyInterface.GetClassesCount(), m_doxyInterface.GetMethodCount());
// build a list of the undocumented wx classes
list.RemoveLast();
list.RemoveLast();
- LogMessage("the list of the %d undocumented wx classes is: %s", undoc, list);
- LogMessage("total processing took %d seconds.", secs);
+ wxLogMessage("the list of the %d undocumented wx classes is: %s", undoc, list);
+ wxLogMessage("total processing took %d seconds.", secs);
}
- /////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
// Name: xmlparser.cpp
// Purpose: Parser of the API/interface XML files
// Author: Francesco Montorsi
if (g_verbose)
{
- LogMessage("Type '%s' does not match type '%s'", m_strType, m.m_strType);
- LogMessage(" => TypeClean %s / %s; IsConst %d / %d; IsStatic %d / %d; IsPointer %d / %d; IsReference %d / %d",
+ wxLogMessage("Type '%s' does not match type '%s'", m_strType, m.m_strType);
+ wxLogMessage(" => TypeClean %s / %s; IsConst %d / %d; IsStatic %d / %d; IsPointer %d / %d; IsReference %d / %d",
m_strTypeClean, m.m_strTypeClean, IsConst(), m.IsConst(),
IsStatic(), m.IsStatic(), IsPointer(), m.IsPointer(),
IsReference(), m.IsReference());
(m.m_strDefaultValueForCmp.IsNumber() && m_strDefaultValueForCmp.StartsWith("wx")))
{
if (g_verbose)
- LogMessage("Supposing '%s' default value to be the same of '%s'...",
+ wxLogMessage("Supposing '%s' default value to be the same of '%s'...",
m_strDefaultValueForCmp, m.m_strDefaultValueForCmp);
return true;
}
if (g_verbose)
- LogMessage("Argument type '%s = %s' has different default value from '%s = %s'",
+ wxLogMessage("Argument type '%s = %s' has different default value from '%s = %s'",
m_strType, m_strDefaultValueForCmp, m.m_strType, m.m_strDefaultValueForCmp);
return false;
}
// NOTE: m_retType can be a wxEmptyType, and means that this method
// is a ctor or a dtor.
if (!m_retType.IsOk() && m_retType!=wxEmptyType) {
- LogError("'%s' method has invalid return type: %s", m_retType.GetAsString());
+ wxLogError("'%s' method has invalid return type: %s", m_retType.GetAsString());
return false;
}
// a function can't be both const and static or virtual and static!
if ((m_bConst && m_bStatic) || ((m_bVirtual || m_bPureVirtual) && m_bStatic)) {
- LogError("'%s' method can't be both const/static or virtual/static", m_strName);
+ wxLogError("'%s' method can't be both const/static or virtual/static", m_strName);
return false;
}
for (unsigned int i=0; i<m_args.GetCount(); i++)
if (!m_args[i].IsOk()) {
- LogError("'%s' method has invalid %d-th argument type: %s",
+ wxLogError("'%s' method has invalid %d-th argument type: %s",
m_strName, i+1, m_args[i].GetAsString());
return false;
}
for (unsigned int i=1; i<m_args.GetCount(); i++)
{
if (previousArgHasDefault && !m_args[i].HasDefaultValue()) {
- LogError("'%s' method has %d-th argument which has no default value "
+ wxLogError("'%s' method has %d-th argument which has no default value "
"(while the previous one had one!)",
m_strName, i+1);
return false;
GetName() != m.GetName())
{
if (g_verbose)
- LogMessage("The method '%s' does not match method '%s'; different names/rettype", GetName(), m.GetName());
+ wxLogMessage("The method '%s' does not match method '%s'; different names/rettype", GetName(), m.GetName());
return false;
}
if (m_args.GetCount()!=m.m_args.GetCount()) {
if (g_verbose)
- LogMessage("Method '%s' has %d arguments while '%s' has %d arguments",
+ wxLogMessage("Method '%s' has %d arguments while '%s' has %d arguments",
m_strName, m_args.GetCount(), m_strName, m.m_args.GetCount());
return false;
}
GetAccessSpecifier() != m.GetAccessSpecifier())
{
if (g_verbose)
- LogMessage("The method '%s' does not match method '%s'; different attributes", GetName(), m.GetName());
+ wxLogMessage("The method '%s' does not match method '%s'; different attributes", GetName(), m.GetName());
return false;
}
for (unsigned int j=0; j<m_methods.GetCount(); j++)
if (i!=j && m_methods[i] == m_methods[j])
{
- LogError("class %s has two methods with the same prototype: '%s'",
+ wxLogError("class %s has two methods with the same prototype: '%s'",
m_strName, m_methods[i].GetAsString());
return false;
{
const wxClass *parent = allclasses->FindClass(m_parents[i]);
if (!parent) {
- LogError("Could not find parent '%s' of class '%s'...",
+ wxLogError("Could not find parent '%s' of class '%s'...",
m_parents[i], GetName());
return false;
}
{
const wxClass *parent = allclasses->FindClass(m_parents[i]);
if (!parent) {
- LogError("Could not find parent '%s' of class '%s'...",
+ wxLogError("Could not find parent '%s' of class '%s'...",
m_parents[i], GetName());
return false;
}
sorted[i]->Dump(apiout);
}
-bool wxXmlInterface::CheckParseResults() const
+bool wxXmlInterface::CheckConsistency() const
{
// this check can be quite slow, so do it only for debug releases:
//#ifdef __WXDEBUG__
for (unsigned int i=0; i<m_classes.GetCount(); i++)
+ {
if (!m_classes[i].CheckConsistency())
return false;
+
+ for (unsigned int j=0; j<m_classes.GetCount(); j++)
+ if (i!=j && m_classes[i].GetName() == m_classes[j].GetName())
+ {
+ wxLogError("two classes have the same name: %s",
+ m_classes[i].GetName());
+ return false;
+ }
+ }
//#endif
return true;
wxXmlNode *child;
int nodes = 0;
- LogMessage("Parsing %s...", filename);
+ wxLogMessage("Parsing %s...", filename);
if (!doc.Load(filename)) {
- LogError("can't load %s", filename);
+ wxLogError("can't load %s", filename);
return false;
}
// start processing the XML file
if (doc.GetRoot()->GetName() != "GCC_XML") {
- LogError("invalid root node for %s", filename);
+ wxLogError("invalid root node for %s", filename);
return false;
}
if (old)
{
- LogError("The version of GCC-XML used for the creation of %s is too old; "
+ wxLogError("The version of GCC-XML used for the creation of %s is too old; "
"the cvs_revision attribute of the root node reports '%s', "
"minimal required is 1.%d.", filename, version, MIN_REVISION);
return false;
// NOTE: <File> nodes can have an id == "f0"...
- LogError("Invalid id for node %s: %s", n, child->GetAttribute("id"));
+ wxLogError("Invalid id for node %s: %s", n, child->GetAttribute("id"));
return false;
}
{
wxString cname = child->GetAttribute("name");
if (cname.IsEmpty()) {
- LogError("Invalid empty name for '%s' node", n);
+ wxLogError("Invalid empty name for '%s' node", n);
return false;
}
if (ids.IsEmpty())
{
if (child->GetAttribute("incomplete") != "1") {
- LogError("Invalid member IDs for '%s' class node: %s",
+ wxLogError("Invalid member IDs for '%s' class node: %s",
cname, child->GetAttribute("id"));
return false;
}
{
// decode the non-empty list of IDs:
if (!getMemberIDs(&members, newClass, ids)) {
- LogError("Invalid member IDs for '%s' class node: %s",
+ wxLogError("Invalid member IDs for '%s' class node: %s",
cname, child->GetAttribute("id"));
return false;
}
{
unsigned long typeId = 0;
if (!getID(&typeId, child->GetAttribute("type"))) {
- LogError("Invalid type for node %s: %s", n, child->GetAttribute("type"));
+ wxLogError("Invalid type for node %s: %s", n, child->GetAttribute("type"));
return false;
}
{
unsigned long type = 0;
if (!getID(&type, child->GetAttribute("type")) || type == 0) {
- LogError("Invalid type for node %s: %s", n, child->GetAttribute("type"));
+ wxLogError("Invalid type for node %s: %s", n, child->GetAttribute("type"));
return false;
}
else if (n == "File")
{
if (!child->GetAttribute("id").StartsWith("f")) {
- LogError("Unexpected file ID: %s", child->GetAttribute("id"));
+ wxLogError("Unexpected file ID: %s", child->GetAttribute("id"));
return false;
}
// they're never used as return/argument types by wxWidgets methods
if (g_verbose)
- LogWarning("Type node '%s' with ID '%s' does not have name attribute",
+ wxLogWarning("Type node '%s' with ID '%s' does not have name attribute",
n, child->GetAttribute("id"));
types[id] = "TOFIX";
while (toResolveTypes.size()>0)
{
if (g_verbose)
- LogMessage("%d types were collected; %d types need yet to be resolved...",
+ wxLogMessage("%d types were collected; %d types need yet to be resolved...",
types.size(), toResolveTypes.size());
for (wxToResolveTypeHashMap::iterator i = toResolveTypes.begin();
}
else
{
- LogError("Cannot solve '%d' reference type!", referenced);
+ wxLogError("Cannot solve '%d' reference type!", referenced);
return false;
}
}
{
unsigned long fileID = 0;
if (!getID(&fileID, m_classes[i].GetHeader()) || fileID == 0) {
- LogError("invalid header id: %s", m_classes[i].GetHeader());
+ wxLogError("invalid header id: %s", m_classes[i].GetHeader());
return false;
}
if (idx == files.end())
{
// this is an error!
- LogError("couldn't find file ID '%s'", m_classes[i].GetHeader());
+ wxLogError("couldn't find file ID '%s'", m_classes[i].GetHeader());
}
else
m_classes[i].SetHeader(idx->second);
unsigned long id;
if (!getID(&id, m_classes[i].GetParent(k))) {
- LogError("invalid parent class ID for '%s'", m_classes[i].GetName());
+ wxLogError("invalid parent class ID for '%s'", m_classes[i].GetName());
return false;
}
if (idx == types.end())
{
// this is an error!
- LogError("couldn't find parent class ID '%d'", id);
+ wxLogError("couldn't find parent class ID '%d'", id);
}
else
// replace k-th parent with its true name:
{
unsigned long id = 0;
if (!getID(&id, child->GetAttribute("id"))) {
- LogError("invalid ID for node '%s' with ID '%s'", n, child->GetAttribute("id"));
+ wxLogError("invalid ID for node '%s' with ID '%s'", n, child->GetAttribute("id"));
return false;
}
// this <Method> node is a method of the i-th class!
wxMethod newfunc;
if (!ParseMethod(child, types, newfunc)) {
- LogError("The method '%s' could not be added to class '%s'",
+ wxLogError("The method '%s' could not be added to class '%s'",
child->GetAttribute("demangled"), p->GetName());
return false;
}
// do some additional check that we can do only here:
if (newfunc.IsCtor() && !p->IsValidCtorForThisClass(newfunc)) {
- LogError("The method '%s' does not seem to be a ctor for '%s'",
+ wxLogError("The method '%s' does not seem to be a ctor for '%s'",
newfunc.GetName(), p->GetName());
return false;
}
if (newfunc.IsDtor() && !p->IsValidDtorForThisClass(newfunc)) {
- LogError("The method '%s' does not seem to be a dtor for '%s'",
+ wxLogError("The method '%s' does not seem to be a dtor for '%s'",
newfunc.GetName(), p->GetName());
return false;
}
if ((++nodes%PROGRESS_RATE)==0) ShowProgress();
}
- if (!CheckParseResults())
- return false;
+ if (!CheckConsistency())
+ return false; // the check failed
return true;
}
if (!getID(&retid, p->GetAttribute("returns")) || retid == 0)
{
if (p->GetName() != "Destructor" && p->GetName() != "Constructor") {
- LogError("Empty return ID for method '%s', with ID '%s'",
+ wxLogError("Empty return ID for method '%s', with ID '%s'",
name, p->GetAttribute("id"));
return false;
}
{
wxTypeIdHashMap::const_iterator retidx = types.find(retid);
if (retidx == types.end()) {
- LogError("Could not find return type ID '%s'", retid);
+ wxLogError("Could not find return type ID '%s'", retid);
return false;
}
ret = wxType(retidx->second);
if (!ret.IsOk()) {
- LogError("Invalid return type '%s' for method '%s', with ID '%s'",
+ wxLogError("Invalid return type '%s' for method '%s', with ID '%s'",
retidx->second, name, p->GetAttribute("id"));
return false;
}
{
unsigned long id = 0;
if (!getID(&id, arg->GetAttribute("type")) || id == 0) {
- LogError("Invalid argument type ID '%s' for method '%s' with ID %s",
+ wxLogError("Invalid argument type ID '%s' for method '%s' with ID %s",
arg->GetAttribute("type"), name, p->GetAttribute("id"));
return false;
}
wxTypeIdHashMap::const_iterator idx = types.find(id);
if (idx == types.end()) {
- LogError("Could not find argument type ID '%s'", id);
+ wxLogError("Could not find argument type ID '%s'", id);
return false;
}
m.SetAccessSpecifier(wxMAS_PRIVATE);
if (!m.IsOk()) {
- LogError("The prototype '%s' is not valid!", m.GetAsString());
+ wxLogError("The prototype '%s' is not valid!", m.GetAsString());
return false;
}
else if (ref->GetType() == wxXML_TEXT_NODE)
text += ref->GetContent();
else
- LogWarning("Unexpected node type while getting text from '%s' node", n->GetName());
+ wxLogWarning("Unexpected node type while getting text from '%s' node", n->GetName());
ref = ref->GetNext();
}
for (unsigned int i=0; i < ports.GetCount(); i++)
{
if (!ports[i].StartsWith("wx")) {
- LogError("unexpected port ID '%s'", ports[i]);
+ wxLogError("unexpected port ID '%s'", ports[i]);
return false;
}
wxXmlDocument index;
wxXmlNode *compound;
- LogMessage("Parsing %s...", filename);
+ wxLogMessage("Parsing %s...", filename);
if (!index.Load(filename)) {
- LogError("can't load %s", filename);
+ wxLogError("can't load %s", filename);
return false;
}
// start processing the index:
if (index.GetRoot()->GetName() != "doxygenindex") {
- LogError("invalid root node for %s", filename);
+ wxLogError("invalid root node for %s", filename);
return false;
}
}
//wxPrint("\n");
- if (!CheckParseResults())
- return false;
+ if (!CheckConsistency())
+ return false; // the check failed
return true;
}
int nodes = 0;
if (g_verbose)
- LogMessage("Parsing %s...", filename);
+ wxLogMessage("Parsing %s...", filename);
if (!doc.Load(filename)) {
- LogError("can't load %s", filename);
+ wxLogError("can't load %s", filename);
return false;
}
// start processing this compound definition XML
if (doc.GetRoot()->GetName() != "doxygen") {
- LogError("invalid root node for %s", filename);
+ wxLogError("invalid root node for %s", filename);
return false;
}
wxMethod m;
if (!ParseMethod(membernode, m, header)) {
- LogError("The method '%s' could not be added to class '%s'",
+ wxLogError("The method '%s' could not be added to class '%s'",
m.GetName(), klass.GetName());
return false;
}
absoluteFile = header;
else if (header != absoluteFile)
{
- LogError("The method '%s' is documented in a different "
+ wxLogError("The method '%s' is documented in a different "
"file from others (which belong to '%s') ?",
header, absoluteFile);
return false;
if (klass.IsOk())
m_classes.Add(klass);
else if (g_verbose)
- LogWarning("discarding class '%s' with %d methods...",
- klass.GetName(), klass.GetMethodCount());
+ wxLogWarning("discarding class '%s' with %d methods...",
+ klass.GetName(), klass.GetMethodCount());
}
child = child->GetNext();
}
if (typestr.IsEmpty()) {
- LogError("cannot find type node for a param in method '%s'", m.GetName());
+ wxLogError("cannot find type node for a param in method '%s'", m.GetName());
return false;
}
m.SetPureVirtual(p->GetAttribute("virt")=="pure-virtual");
if (!m.IsOk()) {
- LogError("The prototype '%s' is not valid!", m.GetAsString());
+ wxLogError("The prototype '%s' is not valid!", m.GetAsString());
return false;
}