📄 helpgen.cpp
字号:
paramsAll << paramTypes[param] << ' ' << paramNames[param];
}
wxString constStr;
if (foundCommand == ConstFunc)
constStr = _T(" const");
wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
m_filename.c_str(),
(int)m_line,
returnType.c_str(),
classname.c_str(),
funcName.c_str(),
paramsAll.c_str(),
constStr.c_str());
// store the info about the just found function
ArrayMethodInfo *methods;
int index = m_classes.Index(classname);
if ( index == wxNOT_FOUND ) {
m_classes.Add(classname);
methods = new ArrayMethodInfo;
m_methods.Add(methods);
}
else {
methods = m_methods[(size_t)index];
}
ArrayParamInfo params;
for ( param = 0; param < paramCount; param++ ) {
params.Add(new ParamInfo(paramTypes[param],
paramNames[param],
paramValues[param]));
}
MethodInfo *method = new MethodInfo(returnType, funcName, params);
if ( foundCommand == ConstFunc )
method->SetFlag(MethodInfo::Const);
if ( isVararg )
method->SetFlag(MethodInfo::Vararg);
methods->Add(method);
}
delete [] buf;
wxLogVerbose("%s: finished parsing doc file '%s'.\n",
GetCurrentTimeFormatted("%H:%M:%S"), m_filename.c_str());
return true;
}
bool DocManager::DumpDifferences(spContext *ctxTop) const
{
typedef MMemberListT::const_iterator MemberIndex;
bool foundDiff = false;
// flag telling us whether the given class was found at all in the header
size_t nClass, countClassesInDocs = m_classes.GetCount();
bool *classExists = new bool[countClassesInDocs];
for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) {
classExists[nClass] = false;
}
// ctxTop is normally an spFile
wxASSERT( ctxTop->GetContextType() == SP_CTX_FILE );
const MMemberListT& classes = ctxTop->GetMembers();
for ( MemberIndex i = classes.begin(); i != classes.end(); i++ ) {
spContext *ctx = *i;
if ( ctx->GetContextType() != SP_CTX_CLASS ) {
// TODO process also global functions, macros, ...
continue;
}
spClass *ctxClass = (spClass *)ctx;
const wxString& nameClass = ctxClass->m_Name;
int index = m_classes.Index(nameClass);
if ( index == wxNOT_FOUND ) {
if ( !m_ignoreNames.IgnoreClass(nameClass) ) {
foundDiff = true;
wxLogError("Class '%s' is not documented at all.",
nameClass.c_str());
}
// it makes no sense to check for its functions
continue;
}
else {
classExists[index] = true;
}
// array of method descriptions for this class
const ArrayMethodInfo& methods = *(m_methods[index]);
size_t nMethod, countMethods = methods.GetCount();
// flags telling if we already processed given function
bool *methodExists = new bool[countMethods];
for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
methodExists[nMethod] = false;
}
wxArrayString aOverloadedMethods;
const MMemberListT& functions = ctxClass->GetMembers();
for ( MemberIndex j = functions.begin(); j != functions.end(); j++ ) {
ctx = *j;
if ( ctx->GetContextType() != SP_CTX_OPERATION )
continue;
spOperation *ctxMethod = (spOperation *)ctx;
const wxString& nameMethod = ctxMethod->m_Name;
// find all functions with the same name
wxArrayInt aMethodsWithSameName;
for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
if ( methods[nMethod]->GetName() == nameMethod )
aMethodsWithSameName.Add(nMethod);
}
if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) {
if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
foundDiff = true;
wxLogError("'%s::%s' is not documented.",
nameClass.c_str(),
nameMethod.c_str());
}
// don't check params
continue;
}
else if ( aMethodsWithSameName.GetCount() == 1 ) {
index = (size_t)aMethodsWithSameName[0u];
methodExists[index] = true;
if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
continue;
if ( !ctxMethod->IsPublic() ) {
wxLogWarning("'%s::%s' is documented but not public.",
nameClass.c_str(),
nameMethod.c_str());
}
// check that the flags match
const MethodInfo& method = *(methods[index]);
bool isVirtual = ctxMethod->mIsVirtual;
if ( isVirtual != method.HasFlag(MethodInfo::Virtual) )
{
wxString virtualStr;
if(isVirtual)virtualStr = _T("not ");
wxLogWarning("'%s::%s' is incorrectly documented as %s"
"virtual.",
nameClass.c_str(),
nameMethod.c_str(),
virtualStr.c_str());
}
bool isConst = ctxMethod->mIsConstant;
if ( isConst != method.HasFlag(MethodInfo::Const) )
{
wxString constStr;
if(isConst)constStr = _T("not ");
wxLogWarning("'%s::%s' is incorrectly documented as %s"
"constant.",
nameClass.c_str(),
nameMethod.c_str(),
constStr.c_str());
}
// check that the params match
const MMemberListT& params = ctxMethod->GetMembers();
if ( params.size() != method.GetParamCount() ) {
wxLogError("Incorrect number of parameters for '%s::%s' "
"in the docs: should be %d instead of %d.",
nameClass.c_str(),
nameMethod.c_str(),
(int)params.size(), (int)method.GetParamCount());
}
else {
size_t nParam = 0;
for ( MemberIndex k = params.begin();
k != params.end();
k++, nParam++ ) {
ctx = *k;
// what else can a function have?
wxASSERT( ctx->GetContextType() == SP_CTX_PARAMETER );
spParameter *ctxParam = (spParameter *)ctx;
const ParamInfo& param = method.GetParam(nParam);
if ( m_checkParamNames &&
(param.GetName() != ctxParam->m_Name.c_str()) ) {
foundDiff = true;
wxLogError("Parameter #%d of '%s::%s' should be "
"'%s' and not '%s'.",
(int)(nParam + 1),
nameClass.c_str(),
nameMethod.c_str(),
ctxParam->m_Name.c_str(),
param.GetName().c_str());
continue;
}
if ( param.GetType() != ctxParam->m_Type ) {
foundDiff = true;
wxLogError("Type of parameter '%s' of '%s::%s' "
"should be '%s' and not '%s'.",
ctxParam->m_Name.c_str(),
nameClass.c_str(),
nameMethod.c_str(),
ctxParam->m_Type.c_str(),
param.GetType().GetName().c_str());
continue;
}
if ( param.GetDefValue() != ctxParam->m_InitVal.c_str() ) {
wxLogWarning("Default value of parameter '%s' of "
"'%s::%s' should be '%s' and not "
"'%s'.",
ctxParam->m_Name.c_str(),
nameClass.c_str(),
nameMethod.c_str(),
ctxParam->m_InitVal.c_str(),
param.GetDefValue().c_str());
}
}
}
}
else {
// TODO OVER add real support for overloaded methods
if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
continue;
if ( aOverloadedMethods.Index(nameMethod) == wxNOT_FOUND ) {
// mark all methods with this name as existing
for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
if ( methods[nMethod]->GetName() == nameMethod )
methodExists[nMethod] = true;
}
aOverloadedMethods.Add(nameMethod);
wxLogVerbose("'%s::%s' is overloaded and I'm too "
"stupid to find the right match - skipping "
"the param and flags checks.",
nameClass.c_str(),
nameMethod.c_str());
}
//else: warning already given
}
}
for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
if ( !methodExists[nMethod] ) {
const wxString& nameMethod = methods[nMethod]->GetName();
if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
foundDiff = true;
wxLogError("'%s::%s' is documented but doesn't exist.",
nameClass.c_str(),
nameMethod.c_str());
}
}
}
delete [] methodExists;
}
// check that all classes we found in the docs really exist
for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) {
if ( !classExists[nClass] ) {
foundDiff = true;
wxLogError("Class '%s' is documented but doesn't exist.",
m_classes[nClass].c_str());
}
}
delete [] classExists;
return !foundDiff;
}
DocManager::~DocManager()
{
WX_CLEAR_ARRAY(m_methods);
}
// ---------------------------------------------------------------------------
// IgnoreNamesHandler implementation
// ---------------------------------------------------------------------------
int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry *first,
IgnoreListEntry *second)
{
// first compare the classes
int rc = first->m_classname.Cmp(second->m_classname);
if ( rc == 0 )
rc = first->m_funcname.Cmp(second->m_funcname);
return rc;
}
bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename)
{
wxFile file(filename, wxFile::read);
if ( !file.IsOpened() )
return false;
off_t len = file.Length();
if ( len == wxInvalidOffset )
return false;
char *buf = new char[len + 1];
buf[len] = '\0';
if ( file.Read(buf, len) == wxInvalidOffset ) {
delete [] buf;
return false;
}
wxString line;
for ( const char *current = buf; ; current++ ) {
#ifdef __WXMSW__
// skip DOS line separator
if ( *current == '\r' )
current++;
#endif // wxMSW
if ( *current == '\n' || *current == '\0' ) {
if ( line[0u] != '#' ) {
if ( line.Find(':') != wxNOT_FOUND ) {
wxString classname = line.BeforeFirst(':'),
funcname = line.AfterLast(':');
m_ignore.Add(new IgnoreListEntry(classname, funcname));
}
else {
// entire class
m_ignore.Add(new IgnoreListEntry(line, wxEmptyString));
}
}
//else: comment
if ( *current == '\0' )
break;
line.Empty();
}
else {
line += *current;
}
}
delete [] buf;
return true;
}
// -----------------------------------------------------------------------------
// global function implementation
// -----------------------------------------------------------------------------
static wxString MakeLabel(const char *classname, const char *funcname)
{
wxString label(classname);
if ( funcname && funcname[0] == '\\' ) {
// we may have some special TeX macro - so far only \destruct exists,
// but may be later others will be added
static const char *macros[] = { "destruct" };
static const char *replacement[] = { "dtor" };
size_t n;
for ( n = 0; n < WXSIZEOF(macros); n++ ) {
if ( strncmp(funcname + 1, macros[n], strlen(macros[n])) == 0 ) {
// found
break;
}
}
if ( n == WXSIZEOF(macros) ) {
wxLogWarning("unknown function name '%s' - leaving as is.",
funcname);
}
else {
funcname = replacement[n];
}
}
if ( funcname ) {
// special treatment for operatorXXX() stuff because the C operators
// are not valid in LaTeX labels
wxString oper;
if ( wxString(funcname).StartsWith("operator", &oper) ) {
label << "operator";
static const struct
{
const char *oper;
const char *name;
} operatorNames[] =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -