From 787cbcb02e5c54282e038333fac0190f79fef73d Mon Sep 17 00:00:00 2001 From: PKEuS Date: Sat, 10 Jan 2015 22:18:57 +0100 Subject: [PATCH] Accept unknown elements in Library files, but print a warning. This fixes backward compatibility of libraries with older cppcheck versions --- cli/cmdlineparser.cpp | 40 +----------------------------- cli/cppcheckexecutor.cpp | 50 ++++++++++++++++++++++++++++++++++--- cli/cppcheckexecutor.h | 7 ++++++ lib/library.cpp | 53 ++++++++++++++++++++++++++-------------- lib/library.h | 2 +- 5 files changed, 91 insertions(+), 61 deletions(-) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 7ea8ca3d4..85d5a8ed8 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -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 diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index cd5701723..7ad27fc93 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -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 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; diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index 24db44b4b..f3e98ae79 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -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: /** diff --git a/lib/library.cpp b/lib/library.cpp index 5f8d83e3b..d7308f30a 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -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 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::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); } diff --git a/lib/library.h b/lib/library.h index 5ff1048bb..3948eff31 100644 --- a/lib/library.h +++ b/lib/library.h @@ -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: