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,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

View File

@ -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;

View File

@ -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:
/** /**

View File

@ -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);
} }

View File

@ -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: