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
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue