Accept unknown elements in Library files, but print a warning. This fixes backward compatibility of libraries with older cppcheck versions
This commit is contained in:
parent
fd2f93bb80
commit
787cbcb02e
|
@ -512,46 +512,8 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
|
||||||
|
|
||||||
// --library
|
// --library
|
||||||
else if (std::strncmp(argv[i], "--library=", 10) == 0) {
|
else if (std::strncmp(argv[i], "--library=", 10) == 0) {
|
||||||
Library::Error err = _settings->library.load(argv[0], argv[i]+10);
|
if (!CppCheckExecutor::tryLoadLibrary(_settings->library, argv[0], argv[i]+10))
|
||||||
std::string errmsg;
|
|
||||||
switch (err.errorcode) {
|
|
||||||
case Library::OK:
|
|
||||||
break;
|
|
||||||
case Library::FILE_NOT_FOUND:
|
|
||||||
errmsg = "File not found";
|
|
||||||
break;
|
|
||||||
case Library::BAD_XML:
|
|
||||||
errmsg = "Bad XML";
|
|
||||||
break;
|
|
||||||
case Library::BAD_ELEMENT:
|
|
||||||
errmsg = "Unexpected element";
|
|
||||||
break;
|
|
||||||
case Library::MISSING_ATTRIBUTE:
|
|
||||||
errmsg = "Missing attribute";
|
|
||||||
break;
|
|
||||||
case Library::BAD_ATTRIBUTE:
|
|
||||||
errmsg = "Bad attribute";
|
|
||||||
break;
|
|
||||||
case Library::BAD_ATTRIBUTE_VALUE:
|
|
||||||
errmsg = "Bad attribute value";
|
|
||||||
break;
|
|
||||||
case Library::UNSUPPORTED_FORMAT:
|
|
||||||
errmsg = "File is of unsupported format version";
|
|
||||||
break;
|
|
||||||
case Library::DUPLICATE_PLATFORM_TYPE:
|
|
||||||
errmsg = "Duplicate platform type";
|
|
||||||
break;
|
|
||||||
case Library::PLATFORM_TYPE_REDEFINED:
|
|
||||||
errmsg = "Platform type redefined";
|
|
||||||
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;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report progress
|
// Report progress
|
||||||
|
|
|
@ -724,13 +724,13 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
|
||||||
{
|
{
|
||||||
Settings& settings = cppcheck.settings();
|
Settings& settings = cppcheck.settings();
|
||||||
_settings = &settings;
|
_settings = &settings;
|
||||||
bool std = (settings.library.load(argv[0], "std.cfg").errorcode == Library::OK);
|
bool std = tryLoadLibrary(settings.library, argv[0], "std.cfg");
|
||||||
bool posix = true;
|
bool posix = true;
|
||||||
if (settings.standards.posix)
|
if (settings.standards.posix)
|
||||||
posix = (settings.library.load(argv[0], "posix.cfg").errorcode == Library::OK);
|
posix = tryLoadLibrary(settings.library, argv[0], "posix.cfg");
|
||||||
bool windows = true;
|
bool windows = true;
|
||||||
if (settings.isWindowsPlatform())
|
if (settings.isWindowsPlatform())
|
||||||
windows = (settings.library.load(argv[0], "windows.cfg").errorcode == Library::OK);
|
windows = tryLoadLibrary(settings.library, argv[0], "windows.cfg");
|
||||||
|
|
||||||
if (!std || !posix || !windows) {
|
if (!std || !posix || !windows) {
|
||||||
const std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
const std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||||
|
@ -908,4 +908,48 @@ const std::string& CppCheckExecutor::getExceptionOutput()
|
||||||
return exceptionOutput;
|
return exceptionOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CppCheckExecutor::tryLoadLibrary(Library& destination, const char* basepath, const char* filename)
|
||||||
|
{
|
||||||
|
Library::Error err = destination.load(basepath, filename);
|
||||||
|
|
||||||
|
if (err.errorcode == Library::UNKNOWN_ELEMENT)
|
||||||
|
std::cout << "cppcheck: Found unknown elements in configuration file '" << filename << "': " << err.reason << std::endl;
|
||||||
|
else if (err.errorcode != Library::OK) {
|
||||||
|
std::string errmsg;
|
||||||
|
switch (err.errorcode) {
|
||||||
|
case Library::OK:
|
||||||
|
break;
|
||||||
|
case Library::FILE_NOT_FOUND:
|
||||||
|
errmsg = "File not found";
|
||||||
|
break;
|
||||||
|
case Library::BAD_XML:
|
||||||
|
errmsg = "Bad XML";
|
||||||
|
break;
|
||||||
|
case Library::UNKNOWN_ELEMENT:
|
||||||
|
errmsg = "Unexpected element";
|
||||||
|
break;
|
||||||
|
case Library::MISSING_ATTRIBUTE:
|
||||||
|
errmsg = "Missing attribute";
|
||||||
|
break;
|
||||||
|
case Library::BAD_ATTRIBUTE_VALUE:
|
||||||
|
errmsg = "Bad attribute value";
|
||||||
|
break;
|
||||||
|
case Library::UNSUPPORTED_FORMAT:
|
||||||
|
errmsg = "File is of unsupported format version";
|
||||||
|
break;
|
||||||
|
case Library::DUPLICATE_PLATFORM_TYPE:
|
||||||
|
errmsg = "Duplicate platform type";
|
||||||
|
break;
|
||||||
|
case Library::PLATFORM_TYPE_REDEFINED:
|
||||||
|
errmsg = "Platform type redefined";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!err.reason.empty())
|
||||||
|
errmsg += " '" + err.reason + "'";
|
||||||
|
std::cout << "cppcheck: Failed to load library configuration file '" << filename << "'. " << errmsg << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CppCheckExecutor::exceptionOutput;
|
std::string CppCheckExecutor::exceptionOutput;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
class CppCheck;
|
class CppCheck;
|
||||||
class Settings;
|
class Settings;
|
||||||
|
class Library;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class works as an example of how CppCheck can be used in external
|
* This class works as an example of how CppCheck can be used in external
|
||||||
|
@ -96,6 +97,12 @@ public:
|
||||||
*/
|
*/
|
||||||
static const std::string& getExceptionOutput();
|
static const std::string& getExceptionOutput();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to load a library and prints warning/error messages
|
||||||
|
* @return false, if an error occured (except unknown XML elements)
|
||||||
|
*/
|
||||||
|
static bool tryLoadLibrary(Library& destination, const char* basepath, const char* filename);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -107,7 +107,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
return Error(BAD_XML);
|
return Error(BAD_XML);
|
||||||
|
|
||||||
if (strcmp(rootnode->Name(),"def") != 0)
|
if (strcmp(rootnode->Name(),"def") != 0)
|
||||||
return Error(BAD_ELEMENT, rootnode->Name());
|
return Error(UNSUPPORTED_FORMAT, rootnode->Name());
|
||||||
|
|
||||||
const char* format_string = rootnode->Attribute("format");
|
const char* format_string = rootnode->Attribute("format");
|
||||||
int format = 1;
|
int format = 1;
|
||||||
|
@ -117,6 +117,8 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
if (format > 1)
|
if (format > 1)
|
||||||
return Error(UNSUPPORTED_FORMAT);
|
return Error(UNSUPPORTED_FORMAT);
|
||||||
|
|
||||||
|
std::set<std::string> unknown_elements;
|
||||||
|
|
||||||
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
|
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
|
||||||
const std::string nodename = node->Name();
|
const std::string nodename = node->Name();
|
||||||
if (nodename == "memory" || nodename == "resource") {
|
if (nodename == "memory" || nodename == "resource") {
|
||||||
|
@ -153,7 +155,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
else if (memorynodename == "use")
|
else if (memorynodename == "use")
|
||||||
use.insert(memorynode->GetText());
|
use.insert(memorynode->GetText());
|
||||||
else
|
else
|
||||||
return Error(BAD_ELEMENT, memorynodename);
|
unknown_elements.insert(memorynodename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +275,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
return Error(BAD_ATTRIBUTE, argnodename);
|
unknown_elements.insert(argnodename);
|
||||||
}
|
}
|
||||||
argumentChecks[name][nr].notbool = notbool;
|
argumentChecks[name][nr].notbool = notbool;
|
||||||
argumentChecks[name][nr].notnull = notnull;
|
argumentChecks[name][nr].notnull = notnull;
|
||||||
|
@ -287,14 +289,16 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
|
const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
|
||||||
_formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue());
|
_formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue());
|
||||||
} else
|
} else
|
||||||
return Error(BAD_ELEMENT, functionnodename);
|
unknown_elements.insert(functionnodename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (nodename == "reflection") {
|
else if (nodename == "reflection") {
|
||||||
for (const tinyxml2::XMLElement *reflectionnode = node->FirstChildElement(); reflectionnode; reflectionnode = reflectionnode->NextSiblingElement()) {
|
for (const tinyxml2::XMLElement *reflectionnode = node->FirstChildElement(); reflectionnode; reflectionnode = reflectionnode->NextSiblingElement()) {
|
||||||
if (strcmp(reflectionnode->Name(), "call") != 0)
|
if (strcmp(reflectionnode->Name(), "call") != 0) {
|
||||||
return Error(BAD_ELEMENT, reflectionnode->Name());
|
unknown_elements.insert(reflectionnode->Name());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const char * const argString = reflectionnode->Attribute("arg");
|
const char * const argString = reflectionnode->Attribute("arg");
|
||||||
if (!argString)
|
if (!argString)
|
||||||
|
@ -325,14 +329,16 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
return Error(MISSING_ATTRIBUTE, "name");
|
return Error(MISSING_ATTRIBUTE, "name");
|
||||||
_keywords[extension].insert(nodeName);
|
_keywords[extension].insert(nodeName);
|
||||||
} else
|
} else
|
||||||
return Error(BAD_ELEMENT, librarynode->Name());
|
unknown_elements.insert(librarynode->Name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (markupnodename == "exported") {
|
else if (markupnodename == "exported") {
|
||||||
for (const tinyxml2::XMLElement *exporter = markupnode->FirstChildElement(); exporter; exporter = exporter->NextSiblingElement()) {
|
for (const tinyxml2::XMLElement *exporter = markupnode->FirstChildElement(); exporter; exporter = exporter->NextSiblingElement()) {
|
||||||
if (strcmp(exporter->Name(), "exporter") != 0)
|
if (strcmp(exporter->Name(), "exporter") != 0) {
|
||||||
return Error(BAD_ELEMENT, exporter->Name());
|
unknown_elements.insert(exporter->Name());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const char * const prefix = exporter->Attribute("prefix");
|
const char * const prefix = exporter->Attribute("prefix");
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
|
@ -345,7 +351,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
else if (ename == "suffix")
|
else if (ename == "suffix")
|
||||||
_exporters[prefix].addSuffix(e->GetText());
|
_exporters[prefix].addSuffix(e->GetText());
|
||||||
else
|
else
|
||||||
return Error(BAD_ELEMENT, ename);
|
unknown_elements.insert(ename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,7 +361,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
if (strcmp(librarynode->Name(), "importer") == 0)
|
if (strcmp(librarynode->Name(), "importer") == 0)
|
||||||
_importers[extension].insert(librarynode->GetText());
|
_importers[extension].insert(librarynode->GetText());
|
||||||
else
|
else
|
||||||
return Error(BAD_ELEMENT, librarynode->Name());
|
unknown_elements.insert(librarynode->Name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,12 +385,12 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
return Error(BAD_ELEMENT, blocknodename);
|
unknown_elements.insert(blocknodename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
return Error(BAD_ELEMENT, markupnodename);
|
unknown_elements.insert(markupnodename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,8 +421,10 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
const std::string containerNodeName = containerNode->Name();
|
const std::string containerNodeName = containerNode->Name();
|
||||||
if (containerNodeName == "size" || containerNodeName == "access" || containerNodeName == "other") {
|
if (containerNodeName == "size" || containerNodeName == "access" || containerNodeName == "other") {
|
||||||
for (const tinyxml2::XMLElement *functionNode = containerNode->FirstChildElement(); functionNode; functionNode = functionNode->NextSiblingElement()) {
|
for (const tinyxml2::XMLElement *functionNode = containerNode->FirstChildElement(); functionNode; functionNode = functionNode->NextSiblingElement()) {
|
||||||
if (std::string(functionNode->Name()) != "function")
|
if (std::string(functionNode->Name()) != "function") {
|
||||||
return Error(BAD_ELEMENT, functionNode->Name());
|
unknown_elements.insert(functionNode->Name());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const char* const functionName = functionNode->Attribute("name");
|
const char* const functionName = functionNode->Attribute("name");
|
||||||
if (!functionName)
|
if (!functionName)
|
||||||
|
@ -486,7 +494,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
if (string)
|
if (string)
|
||||||
container.stdStringLike = std::string(string) == "std-like";
|
container.stdStringLike = std::string(string) == "std-like";
|
||||||
} else
|
} else
|
||||||
return Error(BAD_ELEMENT, containerNodeName);
|
unknown_elements.insert(containerNodeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +542,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
else if (typenodename == "const_ptr")
|
else if (typenodename == "const_ptr")
|
||||||
type._const_ptr = true;
|
type._const_ptr = true;
|
||||||
else
|
else
|
||||||
return Error(BAD_ELEMENT, typenodename);
|
unknown_elements.insert(typenodename);
|
||||||
}
|
}
|
||||||
if (platform.empty()) {
|
if (platform.empty()) {
|
||||||
const PlatformType * const type_ptr = platform_type(type_name, "");
|
const PlatformType * const type_ptr = platform_type(type_name, "");
|
||||||
|
@ -559,7 +567,16 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
return Error(BAD_ELEMENT, nodename);
|
unknown_elements.insert(nodename);
|
||||||
|
}
|
||||||
|
if (!unknown_elements.empty()) {
|
||||||
|
std::string str;
|
||||||
|
for (std::set<std::string>::const_iterator i = unknown_elements.begin(); i != unknown_elements.end();) {
|
||||||
|
str += *i;
|
||||||
|
if (++i != unknown_elements.end())
|
||||||
|
str += ", ";
|
||||||
|
}
|
||||||
|
return Error(UNKNOWN_ELEMENT, str);
|
||||||
}
|
}
|
||||||
return Error(OK);
|
return Error(OK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ class CPPCHECKLIB Library {
|
||||||
public:
|
public:
|
||||||
Library();
|
Library();
|
||||||
|
|
||||||
enum ErrorCode { OK, FILE_NOT_FOUND, BAD_XML, BAD_ELEMENT, MISSING_ATTRIBUTE, BAD_ATTRIBUTE, BAD_ATTRIBUTE_VALUE, UNSUPPORTED_FORMAT, DUPLICATE_PLATFORM_TYPE, PLATFORM_TYPE_REDEFINED };
|
enum ErrorCode { OK, FILE_NOT_FOUND, BAD_XML, UNKNOWN_ELEMENT, MISSING_ATTRIBUTE, BAD_ATTRIBUTE_VALUE, UNSUPPORTED_FORMAT, DUPLICATE_PLATFORM_TYPE, PLATFORM_TYPE_REDEFINED };
|
||||||
|
|
||||||
class Error {
|
class Error {
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in New Issue