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:
PKEuS 2015-01-10 22:18:57 +01:00
parent fd2f93bb80
commit 787cbcb02e
5 changed files with 91 additions and 61 deletions

View File

@ -512,47 +512,9 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
// --library
else if (std::strncmp(argv[i], "--library=", 10) == 0) {
Library::Error err = _settings->library.load(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);
if (!CppCheckExecutor::tryLoadLibrary(_settings->library, argv[0], argv[i]+10))
return false;
}
}
// Report progress
else if (std::strcmp(argv[i], "--report-progress") == 0) {

View File

@ -724,13 +724,13 @@ 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").errorcode == Library::OK);
bool std = tryLoadLibrary(settings.library, argv[0], "std.cfg");
bool posix = true;
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;
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) {
const std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
@ -908,4 +908,48 @@ const std::string& CppCheckExecutor::getExceptionOutput()
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;

View File

@ -26,6 +26,7 @@
class CppCheck;
class Settings;
class Library;
/**
* This class works as an example of how CppCheck can be used in external
@ -96,6 +97,12 @@ public:
*/
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:
/**

View File

@ -107,7 +107,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
return Error(BAD_XML);
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");
int format = 1;
@ -117,6 +117,8 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
if (format > 1)
return Error(UNSUPPORTED_FORMAT);
std::set<std::string> unknown_elements;
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
const std::string nodename = node->Name();
if (nodename == "memory" || nodename == "resource") {
@ -153,7 +155,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
else if (memorynodename == "use")
use.insert(memorynode->GetText());
else
return Error(BAD_ELEMENT, memorynodename);
unknown_elements.insert(memorynodename);
}
}
@ -273,7 +275,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
}
else
return Error(BAD_ATTRIBUTE, argnodename);
unknown_elements.insert(argnodename);
}
argumentChecks[name][nr].notbool = notbool;
argumentChecks[name][nr].notnull = notnull;
@ -287,14 +289,16 @@ Library::Error 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 Error(BAD_ELEMENT, functionnodename);
unknown_elements.insert(functionnodename);
}
}
else if (nodename == "reflection") {
for (const tinyxml2::XMLElement *reflectionnode = node->FirstChildElement(); reflectionnode; reflectionnode = reflectionnode->NextSiblingElement()) {
if (strcmp(reflectionnode->Name(), "call") != 0)
return Error(BAD_ELEMENT, reflectionnode->Name());
if (strcmp(reflectionnode->Name(), "call") != 0) {
unknown_elements.insert(reflectionnode->Name());
continue;
}
const char * const argString = reflectionnode->Attribute("arg");
if (!argString)
@ -325,14 +329,16 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
return Error(MISSING_ATTRIBUTE, "name");
_keywords[extension].insert(nodeName);
} else
return Error(BAD_ELEMENT, librarynode->Name());
unknown_elements.insert(librarynode->Name());
}
}
else if (markupnodename == "exported") {
for (const tinyxml2::XMLElement *exporter = markupnode->FirstChildElement(); exporter; exporter = exporter->NextSiblingElement()) {
if (strcmp(exporter->Name(), "exporter") != 0)
return Error(BAD_ELEMENT, exporter->Name());
if (strcmp(exporter->Name(), "exporter") != 0) {
unknown_elements.insert(exporter->Name());
continue;
}
const char * const prefix = exporter->Attribute("prefix");
if (!prefix)
@ -345,7 +351,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
else if (ename == "suffix")
_exporters[prefix].addSuffix(e->GetText());
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)
_importers[extension].insert(librarynode->GetText());
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
return Error(BAD_ELEMENT, blocknodename);
unknown_elements.insert(blocknodename);
}
}
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();
if (containerNodeName == "size" || containerNodeName == "access" || containerNodeName == "other") {
for (const tinyxml2::XMLElement *functionNode = containerNode->FirstChildElement(); functionNode; functionNode = functionNode->NextSiblingElement()) {
if (std::string(functionNode->Name()) != "function")
return Error(BAD_ELEMENT, functionNode->Name());
if (std::string(functionNode->Name()) != "function") {
unknown_elements.insert(functionNode->Name());
continue;
}
const char* const functionName = functionNode->Attribute("name");
if (!functionName)
@ -486,7 +494,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
if (string)
container.stdStringLike = std::string(string) == "std-like";
} 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")
type._const_ptr = true;
else
return Error(BAD_ELEMENT, typenodename);
unknown_elements.insert(typenodename);
}
if (platform.empty()) {
const PlatformType * const type_ptr = platform_type(type_name, "");
@ -559,7 +567,16 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
}
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);
}

View File

@ -47,7 +47,7 @@ class CPPCHECKLIB Library {
public:
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 {
public: