X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fce3374f3533ed5dda2f26f238649ef197337010..ba3af1010d452862c384beba48b8dfb8de45c908:/utils/ifacecheck/src/ifacecheck.cpp diff --git a/utils/ifacecheck/src/ifacecheck.cpp b/utils/ifacecheck/src/ifacecheck.cpp index 5c6c6b4e63..1ca155fc56 100644 --- a/utils/ifacecheck/src/ifacecheck.cpp +++ b/utils/ifacecheck/src/ifacecheck.cpp @@ -70,6 +70,22 @@ static const wxCmdLineEntryDesc g_cmdLineDesc[] = wxCMD_LINE_DESC_END }; +class IfaceCheckLog : public wxLog +{ +public: + IfaceCheckLog() {} + + void DoLog(wxLogLevel, const wxString& msg, time_t) + { + // send all messages to stdout (normal behaviour is to sent them to stderr) + wxPrintf(msg); + wxPrintf("\n"); + Flush(); + } + + wxSUPPRESS_DOLOG_HIDE_WARNING() +}; + class IfaceCheckApp : public wxAppConsole { public: @@ -82,8 +98,8 @@ public: bool Compare(); int CompareClasses(const wxClass* iface, const wxClass* api); 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 @@ -116,6 +132,10 @@ int IfaceCheckApp::OnRun() 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; @@ -136,22 +156,18 @@ int IfaceCheckApp::OnRun() // in any case set basic std preprocessor #defines: m_doxyInterface.AddPreprocessorValue("NULL", "0"); - //g_bLogEnabled = false; - // parse the two XML files which contain the real and the doxygen interfaces // for wxWidgets API: if (!m_gccInterface.Parse(parser.GetParam(0)) || !m_doxyInterface.Parse(parser.GetParam(1))) return 1; - 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 @@ -191,23 +207,17 @@ int IfaceCheckApp::OnRun() } } -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; iRecursiveUpwardFindMethod(m, &m_gccInterface); + // avoid some false positives: + if (!real && m.ActsAsDefaultCtor()) + { + // build an artificial default ctor for this class: + wxMethod temp(m); + temp.GetArgumentTypes().Clear(); + + // repeat search: + real = api->RecursiveUpwardFindMethod(temp, &m_gccInterface); + } + + // no matches? if (!real) { - bool exit = false; + bool proceed = true; wxMethodPtrArray overloads = api->RecursiveUpwardFindMethodsNamed(m.GetName(), &m_gccInterface); + // avoid false positives: + for (unsigned int k=0; kMatchesExceptForAttributes(m) && + m.IsDeprecated() && !overloads[k]->IsDeprecated()) + { + // maybe the iface method is marked as deprecated but the + // real method is not? + wxMethod tmp(*overloads[k]); + tmp.SetDeprecated(true); + + if (tmp == m) + { + // in this case, we can disregard this warning... the real + // method probably is included in WXWIN_COMPAT sections! + proceed = false; // skip this method + } + } + #define HACK_TO_AUTO_CORRECT_ONLY_METHOD_ATTRIBUTES 0 #if HACK_TO_AUTO_CORRECT_ONLY_METHOD_ATTRIBUTES for (unsigned int k=0; kMatchesExceptForAttributes(m) && - overloads[k]->IsPureVirtual() == m.IsPureVirtual()) + if (overloads[k]->MatchesExceptForAttributes(m)) { // fix default values of results[k]: wxMethod tmp(*overloads[k]); @@ -319,96 +358,100 @@ int IfaceCheckApp::CompareClasses(const wxClass* iface, const wxClass* api) // 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()); - exit = true; + proceed = false; break; } +#endif // HACK_TO_AUTO_CORRECT_ONLY_METHOD_ATTRIBUTES - if (!exit) - { -#endif - - if (overloads.GetCount()==0) - { - LogMessage("%s: real '%s' class and their parents have no method '%s'", - header, api->GetName(), m.GetAsString()); - // we've found no overloads - } - else + if (proceed) { - // first, output a warning - wxString warning = header; - 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(), api->GetName()); - else { - warning += wxString::Format(": in the real headers there is a method '%s' for '%s'" - " but has different signature:\n", - m.GetName(), api->GetName()); - } - - // get a list of the prototypes with _all_ possible attributes: - warning += "\tdoxy header: " + m.GetAsString(true, true, true, true); - for (unsigned int j=0; jGetAsString(true, true, true, true); - - wxPrint(warning + "\n"); - count++; - - if (overloads.GetCount()>1) + if (overloads.GetCount()==0) { - // 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"); + wxLogMessage("%s: real '%s' class and their parents have no method '%s'", + header, api->GetName(), m.GetAsString()); + // we've found no overloads } else { - wxASSERT(overloads.GetCount() == 1); + // first, output a warning + wxString warning = header; + 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(), api->GetName()); + else { + warning += wxString::Format(": in the real headers there is a method '%s' for '%s'" + " but has different signature:\n", + m.GetName(), api->GetName()); + } - if (m_modify) + // get a list of the prototypes with _all_ possible attributes: + warning += "\tdoxy header: " + m.GetAsString(true, true, true, true); + for (unsigned int j=0; jGetAsString(true, true, true, true); + + wxLogWarning("%s", 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) + wxLogWarning("\tmanual fix is required"); + } + else { - wxPrint("\tfixing it...\n"); + wxASSERT(overloads.GetCount() == 1); - // try to modify it! - FixMethod(iface->GetHeader(), &m, overloads[0]); + if (m_modify || m.IsCtor()) + { + wxLogWarning("\tfixing it..."); + + // try to modify it! + FixMethod(iface->GetHeader(), &m, overloads[0]); + } } } - } - count++; - -#if HACK_TO_AUTO_CORRECT_ONLY_METHOD_ATTRIBUTES - } -#endif + count++; + } // if (proceed) } } return count; } +bool IfaceCheckApp::StringContainsMethodName(const wxString& str, const wxMethod* m) +{ + return str.Contains(m->GetName()) || + (m->IsOperator() && str.Contains("operator")); +} + bool IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, const wxMethod* api) { + unsigned int i,j; wxASSERT(iface && api); 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; } - // 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; + // 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; } @@ -416,7 +459,7 @@ bool IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, con // is this a one-line prototype declaration? bool founddecl = false; int start; - if (file.GetLine(end).Contains(iface->GetName())) + if (StringContainsMethodName(file.GetLine(end), iface)) { // yes, this prototype is all on this line: start = end; @@ -424,32 +467,32 @@ bool IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, con } else { - start = end-1; + start = end; // will be decremented inside the while{} loop below - // find the start point of this prototype declaration: - while (start > 0 && - !file.GetLine(start).Contains(";") && - !file.GetLine(start).Contains("*/")) + // find the start point of this prototype declaration; i.e. the line + // containing the function name, which is also the line following + // the marker '*/' for the closure of the doxygen comment + do { - start--; + start--; // go up one line - founddecl |= file.GetLine(start).Contains(iface->GetName()); + if (StringContainsMethodName(file.GetLine(start), iface)) + founddecl = true; } - - // start-th line contains either the declaration of another prototype - // or the closing tag */ of a doxygen comment; start one line below - start++; + while (start > 0 && !founddecl && + !file.GetLine(start).Contains(";") && + !file.GetLine(start).Contains("*/")); } if (start <= 0 || !founddecl) { - LogError("\tcan't find the beginning of the declaration of '%s' method in '%s' header looking backwards from line %d", - iface->GetAsString(), header, end); + 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; } // remove the old prototype - for (int i=start; i<=end; i++) + for (int k=start; k<=end; k++) file.RemoveLine(start); // remove (end-start)-nth times the start-th line #define INDENTATION_STR wxString(" ") @@ -470,15 +513,23 @@ bool IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, con wxMethod tmp(*api); - // discard API argument names and replace them with those parsed from doxygen XML: + // discard gcc XML argument names and replace them with those parsed from doxygen XML; + // in this way we should avoid introducing doxygen warnings about cases where the argument + // 'xx' of the prototype is called 'yy' in the function's docs. const wxArgumentTypeArray& doxygenargs = iface->GetArgumentTypes(); const wxArgumentTypeArray& realargs = api->GetArgumentTypes(); if (realargs.GetCount() == doxygenargs.GetCount()) { - for (unsigned int j=0; j WRAP_COLUMN) @@ -511,12 +562,12 @@ bool IfaceCheckApp::FixMethod(const wxString& header, const wxMethod* iface, con } // insert the new lines - for (unsigned int i=0; iGetMethodCount(); j++) + for (j=0; j < cToUpdate[i]->GetMethodCount(); j++) { wxMethod& m = cToUpdate[i]->GetMethod(j); if (m.GetLocation() > iface->GetLocation()) @@ -551,7 +602,7 @@ bool IfaceCheckApp::ParsePreprocessorOutput(const wxString& filename) { 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; } @@ -564,7 +615,7 @@ bool IfaceCheckApp::ParsePreprocessorOutput(const wxString& filename) // 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; } @@ -593,7 +644,7 @@ bool IfaceCheckApp::ParsePreprocessorOutput(const wxString& filename) } } - 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; @@ -601,10 +652,29 @@ bool IfaceCheckApp::ParsePreprocessorOutput(const wxString& filename) void IfaceCheckApp::PrintStatistics(long secs) { - LogMessage("wx real headers contains declaration of %d classes (%d methods)", + // these stats, for what regards the gcc XML, are all referred to the wxWidgets + // classes only! + + 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()); - LogMessage("total processing took %d seconds.", secs); + + // build a list of the undocumented wx classes + wxString list; + int undoc = 0; + const wxClassArray& arr = m_gccInterface.GetClasses(); + for (unsigned int i=0; i