Library: Better error reporting when loading fails
This commit is contained in:
parent
1cb14f687f
commit
ed78d3e148
|
@ -504,8 +504,35 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
|
|||
|
||||
// --library
|
||||
else if (std::strncmp(argv[i], "--library=", 10) == 0) {
|
||||
if (!_settings->library.load(argv[0], argv[i]+10)) {
|
||||
PrintMessage("cppcheck: Failed to load library configuration file '" + std::string(argv[i]+10) + "'");
|
||||
Library::Error err = _settings->library.load(argv[0], argv[i]+10);
|
||||
std::string errmsg;
|
||||
switch (err.errorcode) {
|
||||
case Library::ErrorCode::OK:
|
||||
break;
|
||||
case Library::ErrorCode::FILE_NOT_FOUND:
|
||||
errmsg = "File not found";
|
||||
break;
|
||||
case Library::ErrorCode::BAD_XML:
|
||||
errmsg = "Bad XML";
|
||||
break;
|
||||
case Library::ErrorCode::BAD_ELEMENT:
|
||||
errmsg = "Unexpected element";
|
||||
break;
|
||||
case Library::ErrorCode::MISSING_ATTRIBUTE:
|
||||
errmsg = "Missing attribute";
|
||||
break;
|
||||
case Library::ErrorCode::BAD_ATTRIBUTE:
|
||||
errmsg = "Bad attribute";
|
||||
break;
|
||||
case Library::ErrorCode::BAD_ATTRIBUTE_VALUE:
|
||||
errmsg = "Bad attribute value";
|
||||
break;
|
||||
}
|
||||
if (!err.reason.empty())
|
||||
errmsg += " '" + err.reason + "'";
|
||||
|
||||
if (!errmsg.empty()) {
|
||||
PrintMessage("cppcheck: Failed to load library configuration file '" + std::string(argv[i]+10) + "'. " + errmsg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -480,10 +480,10 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
|
|||
{
|
||||
Settings& settings = cppcheck.settings();
|
||||
_settings = &settings;
|
||||
bool std = settings.library.load(argv[0], "std.cfg");
|
||||
bool std = (settings.library.load(argv[0], "std.cfg").errorcode == Library::ErrorCode::OK);
|
||||
bool posix = true;
|
||||
if (settings.standards.posix)
|
||||
posix = settings.library.load(argv[0], "posix.cfg");
|
||||
posix = (settings.library.load(argv[0], "posix.cfg").errorcode == Library::ErrorCode::OK);
|
||||
|
||||
if (!std || !posix) {
|
||||
const std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||
|
|
|
@ -518,23 +518,23 @@ bool MainWindow::LoadLibrary(Library *library, QString filename)
|
|||
// Try to load the library from the project folder..
|
||||
if (mProject) {
|
||||
QString path = QFileInfo(mProject->GetProjectFile()->GetFilename()).canonicalPath();
|
||||
if (library->load(NULL, (path+"/"+filename).toLatin1()))
|
||||
if (library->load(NULL, (path+"/"+filename).toLatin1()).errorcode == Library::ErrorCode::OK)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to load the library from the application folder..
|
||||
const QString appPath = QFileInfo(QCoreApplication::applicationFilePath()).canonicalPath();
|
||||
if (library->load(NULL, (appPath+"/"+filename).toLatin1()))
|
||||
if (library->load(NULL, (appPath+"/"+filename).toLatin1()).errorcode == Library::ErrorCode::OK)
|
||||
return true;
|
||||
if (library->load(NULL, (appPath+"/cfg/"+filename).toLatin1()))
|
||||
if (library->load(NULL, (appPath+"/cfg/"+filename).toLatin1()).errorcode == Library::ErrorCode::OK)
|
||||
return true;
|
||||
|
||||
// Try to load the library from the cfg subfolder..
|
||||
const QString datadir = mSettings->value("DATADIR", QString()).toString();
|
||||
if (!datadir.isEmpty()) {
|
||||
if (library->load(NULL, (datadir+"/"+filename).toLatin1()))
|
||||
if (library->load(NULL, (datadir+"/"+filename).toLatin1()).errorcode == Library::ErrorCode::OK)
|
||||
return true;
|
||||
if (library->load(NULL, (datadir+"/cfg/"+filename).toLatin1()))
|
||||
if (library->load(NULL, (datadir+"/cfg/"+filename).toLatin1()).errorcode == Library::ErrorCode::OK)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,19 +30,20 @@ Library::Library() : allocid(0)
|
|||
{
|
||||
}
|
||||
|
||||
bool Library::load(const char exename[], const char path[])
|
||||
Library::Error Library::load(const char exename[], const char path[])
|
||||
{
|
||||
if (std::strchr(path,',') != nullptr) {
|
||||
bool ret = true;
|
||||
std::string p(path);
|
||||
while (p.find(",") != std::string::npos) {
|
||||
const std::string::size_type pos = p.find(",");
|
||||
ret &= load(exename, p.substr(0,pos).c_str());
|
||||
const Error &e = load(exename, p.substr(0,pos).c_str());
|
||||
if (e.errorcode != ErrorCode::OK)
|
||||
return e;
|
||||
p = p.substr(pos+1);
|
||||
}
|
||||
if (!p.empty())
|
||||
ret &= load(exename, p.c_str());
|
||||
return ret;
|
||||
return load(exename, p.c_str());
|
||||
return Error();
|
||||
}
|
||||
|
||||
// open file..
|
||||
|
@ -62,7 +63,7 @@ bool Library::load(const char exename[], const char path[])
|
|||
const std::string cfgfolder(CFGDIR);
|
||||
#else
|
||||
if (!exename)
|
||||
return false;
|
||||
return Error(ErrorCode::FILE_NOT_FOUND);
|
||||
const std::string cfgfolder(Path::fromNativeSeparators(Path::getPathFromFilename(exename)) + "cfg");
|
||||
#endif
|
||||
const char *sep = (!cfgfolder.empty() && cfgfolder[cfgfolder.size()-1U]=='/' ? "" : "/");
|
||||
|
@ -71,24 +72,24 @@ bool Library::load(const char exename[], const char path[])
|
|||
}
|
||||
}
|
||||
|
||||
return (error == tinyxml2::XML_NO_ERROR) && load(doc);
|
||||
return (error == tinyxml2::XML_NO_ERROR) ? load(doc) : Error(ErrorCode::BAD_XML);
|
||||
}
|
||||
|
||||
bool Library::loadxmldata(const char xmldata[], std::size_t len)
|
||||
{
|
||||
tinyxml2::XMLDocument doc;
|
||||
return (tinyxml2::XML_NO_ERROR == doc.Parse(xmldata, len)) && load(doc);
|
||||
return (tinyxml2::XML_NO_ERROR == doc.Parse(xmldata, len)) && (load(doc).errorcode == ErrorCode::OK);
|
||||
}
|
||||
|
||||
bool Library::load(const tinyxml2::XMLDocument &doc)
|
||||
Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||
{
|
||||
const tinyxml2::XMLElement * const rootnode = doc.FirstChildElement();
|
||||
|
||||
if (rootnode == nullptr)
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_XML);
|
||||
|
||||
if (strcmp(rootnode->Name(),"def") != 0)
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, rootnode->Name());
|
||||
|
||||
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
|
||||
if (strcmp(node->Name(),"memory")==0 || strcmp(node->Name(),"resource")==0) {
|
||||
|
@ -124,17 +125,17 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
else if (strcmp(memorynode->Name(),"use")==0)
|
||||
use.insert(memorynode->GetText());
|
||||
else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, memorynode->Name());
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp(node->Name(),"define")==0) {
|
||||
const char *name = node->Attribute("name");
|
||||
if (name == nullptr)
|
||||
return false;
|
||||
return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
|
||||
const char *value = node->Attribute("value");
|
||||
if (value == nullptr)
|
||||
return false;
|
||||
return Error(ErrorCode::MISSING_ATTRIBUTE, "value");
|
||||
defines.push_back(std::string("#define ") +
|
||||
name +
|
||||
" " +
|
||||
|
@ -145,7 +146,7 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
else if (strcmp(node->Name(),"function")==0) {
|
||||
const char *name = node->Attribute("name");
|
||||
if (name == nullptr)
|
||||
return false;
|
||||
return Error(ErrorCode::MISSING_ATTRIBUTE, "name");
|
||||
|
||||
for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) {
|
||||
if (strcmp(functionnode->Name(),"noreturn")==0)
|
||||
|
@ -181,7 +182,7 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
// Validate the validation expression
|
||||
const char *p = argnode->GetText();
|
||||
if (!std::isdigit(*p))
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, argnode->GetText());
|
||||
for (; *p; p++) {
|
||||
if (std::isdigit(*p))
|
||||
continue;
|
||||
|
@ -189,7 +190,7 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
continue;
|
||||
if (*p == ',' && *(p+1) != ',')
|
||||
continue;
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, argnode->GetText());
|
||||
}
|
||||
|
||||
// Set validation expression
|
||||
|
@ -197,7 +198,7 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
}
|
||||
|
||||
else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ATTRIBUTE, argnode->Name());
|
||||
}
|
||||
argumentChecks[name][nr].notbool = notbool;
|
||||
argumentChecks[name][nr].notnull = notnull;
|
||||
|
@ -212,18 +213,18 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
|
||||
_formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue());
|
||||
} else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, functionnode->Name());
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp(node->Name(), "reflection") == 0) {
|
||||
for (const tinyxml2::XMLElement *reflectionnode = node->FirstChildElement(); reflectionnode; reflectionnode = reflectionnode->NextSiblingElement()) {
|
||||
if (strcmp(reflectionnode->Name(), "call") != 0)
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, reflectionnode->Name());
|
||||
|
||||
const char * const argString = reflectionnode->Attribute("arg");
|
||||
if (!argString)
|
||||
return false;
|
||||
return Error(ErrorCode::MISSING_ATTRIBUTE, "arg");
|
||||
|
||||
_reflection[reflectionnode->GetText()] = atoi(argString);
|
||||
}
|
||||
|
@ -232,7 +233,7 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
else if (strcmp(node->Name(), "markup") == 0) {
|
||||
const char * const extension = node->Attribute("ext");
|
||||
if (!extension)
|
||||
return false;
|
||||
return Error(ErrorCode::MISSING_ATTRIBUTE, "ext");
|
||||
_markupExtensions.insert(extension);
|
||||
|
||||
const char * const reporterrors = node->Attribute("reporterrors");
|
||||
|
@ -246,18 +247,18 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
if (strcmp(librarynode->Name(), "keyword") == 0)
|
||||
_keywords[extension].insert(librarynode->Attribute("name"));
|
||||
else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, librarynode->Name());
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp(markupnode->Name(), "exported") == 0) {
|
||||
for (const tinyxml2::XMLElement *exporter = markupnode->FirstChildElement(); exporter; exporter = exporter->NextSiblingElement()) {
|
||||
if (strcmp(exporter->Name(), "exporter") != 0)
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, exporter->Name());
|
||||
|
||||
const char * const prefix = exporter->Attribute("prefix");
|
||||
if (!prefix)
|
||||
return false;
|
||||
return Error(ErrorCode::MISSING_ATTRIBUTE, "prefix");
|
||||
|
||||
for (const tinyxml2::XMLElement *e = exporter->FirstChildElement(); e; e = e->NextSiblingElement()) {
|
||||
if (strcmp(e->Name(), "prefix") == 0)
|
||||
|
@ -265,7 +266,7 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
else if (strcmp(e->Name(), "suffix") == 0)
|
||||
_exporters[prefix].addSuffix(e->GetText());
|
||||
else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, e->Name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,7 +276,7 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
if (strcmp(librarynode->Name(), "importer") == 0)
|
||||
_importers[extension].insert(librarynode->GetText());
|
||||
else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, librarynode->Name());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,19 +298,19 @@ bool Library::load(const tinyxml2::XMLDocument &doc)
|
|||
}
|
||||
|
||||
else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, blocknode->Name());
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, markupnode->Name());
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
return false;
|
||||
return Error(ErrorCode::BAD_ELEMENT, node->Name());
|
||||
}
|
||||
return true;
|
||||
return Error(ErrorCode::OK);
|
||||
}
|
||||
|
||||
bool Library::isargvalid(const std::string &functionName, int argnr, const MathLib::bigint argvalue) const
|
||||
|
|
|
@ -46,9 +46,22 @@ class CPPCHECKLIB Library {
|
|||
public:
|
||||
Library();
|
||||
|
||||
bool load(const char exename [], const char path []);
|
||||
enum ErrorCode { OK, FILE_NOT_FOUND, BAD_XML, BAD_ELEMENT, MISSING_ATTRIBUTE, BAD_ATTRIBUTE, BAD_ATTRIBUTE_VALUE };
|
||||
|
||||
class Error {
|
||||
public:
|
||||
Error() : errorcode(ErrorCode::OK) , reason("") {}
|
||||
explicit Error(ErrorCode e) : errorcode(e) , reason("") {}
|
||||
Error(ErrorCode e, const std::string &r) : errorcode(e), reason(r) {}
|
||||
ErrorCode errorcode;
|
||||
std::string reason;
|
||||
};
|
||||
|
||||
Error load(const char exename [], const char path []);
|
||||
Error load(const tinyxml2::XMLDocument &doc);
|
||||
|
||||
/** this is primarily meant for unit tests. it only returns true/false */
|
||||
bool loadxmldata(const char xmldata[], std::size_t len);
|
||||
bool load(const tinyxml2::XMLDocument &doc);
|
||||
|
||||
/** get allocation id for function by name */
|
||||
int alloc(const char name[]) const {
|
||||
|
|
|
@ -493,7 +493,7 @@ private:
|
|||
errout.str("");
|
||||
|
||||
Settings settings;
|
||||
if (!settings.library.load("./testrunner", "../cfg/std.cfg") && !settings.library.load("./testrunner", "cfg/std.cfg")) {
|
||||
if ((settings.library.load("./testrunner", "../cfg/std.cfg").errorcode != Library::ErrorCode::OK) && (settings.library.load("./testrunner", "cfg/std.cfg").errorcode != Library::ErrorCode::OK)) {
|
||||
complainMissingLib("std.cfg");
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -85,9 +85,9 @@ public:
|
|||
#define REGISTER_TEST( CLASSNAME ) namespace { CLASSNAME instance; }
|
||||
|
||||
#ifdef _WIN32
|
||||
#define LOAD_LIB_2( LIB, NAME ) { if (!(LIB).load("./testrunner", "../cfg/" NAME) && !(LIB).load("./testrunner", "cfg/" NAME)) { complainMissingLib(NAME); return; } }
|
||||
#define LOAD_LIB_2( LIB, NAME ) { if (((LIB).load("./testrunner", "../cfg/" NAME).errorcode != Library::ErrorCode::OK) && ((LIB).load("./testrunner", "cfg/" NAME).errorcode != Library::ErrorCode::OK)) { complainMissingLib(NAME); return; } }
|
||||
#else
|
||||
#define LOAD_LIB_2( LIB, NAME ) { if (!(LIB).load("./testrunner", "cfg/" NAME)) { complainMissingLib(NAME); return; } }
|
||||
#define LOAD_LIB_2( LIB, NAME ) { if ((LIB).load("./testrunner", "cfg/" NAME).errorcode != Library::ErrorCode::OK) { complainMissingLib(NAME); return; } }
|
||||
#endif
|
||||
#define LOAD_LIB( NAME ) { LOAD_LIB_2(_lib, NAME); }
|
||||
|
||||
|
|
Loading…
Reference in New Issue