Skip to content

Commit 787cbcb

Browse files
committed
Accept unknown elements in Library files, but print a warning. This fixes backward compatibility of libraries with older cppcheck versions
1 parent fd2f93b commit 787cbcb

File tree

5 files changed

+91
-61
lines changed

5 files changed

+91
-61
lines changed

cli/cmdlineparser.cpp

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -512,46 +512,8 @@ bool CmdLineParser::ParseFromArgs(int argc, const char* const argv[])
512512

513513
// --library
514514
else if (std::strncmp(argv[i], "--library=", 10) == 0) {
515-
Library::Error err = _settings->library.load(argv[0], argv[i]+10);
516-
std::string errmsg;
517-
switch (err.errorcode) {
518-
case Library::OK:
519-
break;
520-
case Library::FILE_NOT_FOUND:
521-
errmsg = "File not found";
522-
break;
523-
case Library::BAD_XML:
524-
errmsg = "Bad XML";
525-
break;
526-
case Library::BAD_ELEMENT:
527-
errmsg = "Unexpected element";
528-
break;
529-
case Library::MISSING_ATTRIBUTE:
530-
errmsg = "Missing attribute";
531-
break;
532-
case Library::BAD_ATTRIBUTE:
533-
errmsg = "Bad attribute";
534-
break;
535-
case Library::BAD_ATTRIBUTE_VALUE:
536-
errmsg = "Bad attribute value";
537-
break;
538-
case Library::UNSUPPORTED_FORMAT:
539-
errmsg = "File is of unsupported format version";
540-
break;
541-
case Library::DUPLICATE_PLATFORM_TYPE:
542-
errmsg = "Duplicate platform type";
543-
break;
544-
case Library::PLATFORM_TYPE_REDEFINED:
545-
errmsg = "Platform type redefined";
546-
break;
547-
}
548-
if (!err.reason.empty())
549-
errmsg += " '" + err.reason + "'";
550-
551-
if (!errmsg.empty()) {
552-
PrintMessage("cppcheck: Failed to load library configuration file '" + std::string(argv[i]+10) + "'. " + errmsg);
515+
if (!CppCheckExecutor::tryLoadLibrary(_settings->library, argv[0], argv[i]+10))
553516
return false;
554-
}
555517
}
556518

557519
// Report progress

cli/cppcheckexecutor.cpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -724,13 +724,13 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
724724
{
725725
Settings& settings = cppcheck.settings();
726726
_settings = &settings;
727-
bool std = (settings.library.load(argv[0], "std.cfg").errorcode == Library::OK);
727+
bool std = tryLoadLibrary(settings.library, argv[0], "std.cfg");
728728
bool posix = true;
729729
if (settings.standards.posix)
730-
posix = (settings.library.load(argv[0], "posix.cfg").errorcode == Library::OK);
730+
posix = tryLoadLibrary(settings.library, argv[0], "posix.cfg");
731731
bool windows = true;
732732
if (settings.isWindowsPlatform())
733-
windows = (settings.library.load(argv[0], "windows.cfg").errorcode == Library::OK);
733+
windows = tryLoadLibrary(settings.library, argv[0], "windows.cfg");
734734

735735
if (!std || !posix || !windows) {
736736
const std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
@@ -908,4 +908,48 @@ const std::string& CppCheckExecutor::getExceptionOutput()
908908
return exceptionOutput;
909909
}
910910

911+
bool CppCheckExecutor::tryLoadLibrary(Library& destination, const char* basepath, const char* filename)
912+
{
913+
Library::Error err = destination.load(basepath, filename);
914+
915+
if (err.errorcode == Library::UNKNOWN_ELEMENT)
916+
std::cout << "cppcheck: Found unknown elements in configuration file '" << filename << "': " << err.reason << std::endl;
917+
else if (err.errorcode != Library::OK) {
918+
std::string errmsg;
919+
switch (err.errorcode) {
920+
case Library::OK:
921+
break;
922+
case Library::FILE_NOT_FOUND:
923+
errmsg = "File not found";
924+
break;
925+
case Library::BAD_XML:
926+
errmsg = "Bad XML";
927+
break;
928+
case Library::UNKNOWN_ELEMENT:
929+
errmsg = "Unexpected element";
930+
break;
931+
case Library::MISSING_ATTRIBUTE:
932+
errmsg = "Missing attribute";
933+
break;
934+
case Library::BAD_ATTRIBUTE_VALUE:
935+
errmsg = "Bad attribute value";
936+
break;
937+
case Library::UNSUPPORTED_FORMAT:
938+
errmsg = "File is of unsupported format version";
939+
break;
940+
case Library::DUPLICATE_PLATFORM_TYPE:
941+
errmsg = "Duplicate platform type";
942+
break;
943+
case Library::PLATFORM_TYPE_REDEFINED:
944+
errmsg = "Platform type redefined";
945+
break;
946+
}
947+
if (!err.reason.empty())
948+
errmsg += " '" + err.reason + "'";
949+
std::cout << "cppcheck: Failed to load library configuration file '" << filename << "'. " << errmsg << std::endl;
950+
return false;
951+
}
952+
return true;
953+
}
954+
911955
std::string CppCheckExecutor::exceptionOutput;

cli/cppcheckexecutor.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
class CppCheck;
2828
class Settings;
29+
class Library;
2930

3031
/**
3132
* This class works as an example of how CppCheck can be used in external
@@ -96,6 +97,12 @@ class CppCheckExecutor : public ErrorLogger {
9697
*/
9798
static const std::string& getExceptionOutput();
9899

100+
/**
101+
* Tries to load a library and prints warning/error messages
102+
* @return false, if an error occured (except unknown XML elements)
103+
*/
104+
static bool tryLoadLibrary(Library& destination, const char* basepath, const char* filename);
105+
99106
protected:
100107

101108
/**

lib/library.cpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
107107
return Error(BAD_XML);
108108

109109
if (strcmp(rootnode->Name(),"def") != 0)
110-
return Error(BAD_ELEMENT, rootnode->Name());
110+
return Error(UNSUPPORTED_FORMAT, rootnode->Name());
111111

112112
const char* format_string = rootnode->Attribute("format");
113113
int format = 1;
@@ -117,6 +117,8 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
117117
if (format > 1)
118118
return Error(UNSUPPORTED_FORMAT);
119119

120+
std::set<std::string> unknown_elements;
121+
120122
for (const tinyxml2::XMLElement *node = rootnode->FirstChildElement(); node; node = node->NextSiblingElement()) {
121123
const std::string nodename = node->Name();
122124
if (nodename == "memory" || nodename == "resource") {
@@ -153,7 +155,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
153155
else if (memorynodename == "use")
154156
use.insert(memorynode->GetText());
155157
else
156-
return Error(BAD_ELEMENT, memorynodename);
158+
unknown_elements.insert(memorynodename);
157159
}
158160
}
159161

@@ -273,7 +275,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
273275
}
274276

275277
else
276-
return Error(BAD_ATTRIBUTE, argnodename);
278+
unknown_elements.insert(argnodename);
277279
}
278280
argumentChecks[name][nr].notbool = notbool;
279281
argumentChecks[name][nr].notnull = notnull;
@@ -287,14 +289,16 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
287289
const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure");
288290
_formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue());
289291
} else
290-
return Error(BAD_ELEMENT, functionnodename);
292+
unknown_elements.insert(functionnodename);
291293
}
292294
}
293295

294296
else if (nodename == "reflection") {
295297
for (const tinyxml2::XMLElement *reflectionnode = node->FirstChildElement(); reflectionnode; reflectionnode = reflectionnode->NextSiblingElement()) {
296-
if (strcmp(reflectionnode->Name(), "call") != 0)
297-
return Error(BAD_ELEMENT, reflectionnode->Name());
298+
if (strcmp(reflectionnode->Name(), "call") != 0) {
299+
unknown_elements.insert(reflectionnode->Name());
300+
continue;
301+
}
298302

299303
const char * const argString = reflectionnode->Attribute("arg");
300304
if (!argString)
@@ -325,14 +329,16 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
325329
return Error(MISSING_ATTRIBUTE, "name");
326330
_keywords[extension].insert(nodeName);
327331
} else
328-
return Error(BAD_ELEMENT, librarynode->Name());
332+
unknown_elements.insert(librarynode->Name());
329333
}
330334
}
331335

332336
else if (markupnodename == "exported") {
333337
for (const tinyxml2::XMLElement *exporter = markupnode->FirstChildElement(); exporter; exporter = exporter->NextSiblingElement()) {
334-
if (strcmp(exporter->Name(), "exporter") != 0)
335-
return Error(BAD_ELEMENT, exporter->Name());
338+
if (strcmp(exporter->Name(), "exporter") != 0) {
339+
unknown_elements.insert(exporter->Name());
340+
continue;
341+
}
336342

337343
const char * const prefix = exporter->Attribute("prefix");
338344
if (!prefix)
@@ -345,7 +351,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
345351
else if (ename == "suffix")
346352
_exporters[prefix].addSuffix(e->GetText());
347353
else
348-
return Error(BAD_ELEMENT, ename);
354+
unknown_elements.insert(ename);
349355
}
350356
}
351357
}
@@ -355,7 +361,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
355361
if (strcmp(librarynode->Name(), "importer") == 0)
356362
_importers[extension].insert(librarynode->GetText());
357363
else
358-
return Error(BAD_ELEMENT, librarynode->Name());
364+
unknown_elements.insert(librarynode->Name());
359365
}
360366
}
361367

@@ -379,12 +385,12 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
379385
}
380386

381387
else
382-
return Error(BAD_ELEMENT, blocknodename);
388+
unknown_elements.insert(blocknodename);
383389
}
384390
}
385391

386392
else
387-
return Error(BAD_ELEMENT, markupnodename);
393+
unknown_elements.insert(markupnodename);
388394
}
389395
}
390396

@@ -415,8 +421,10 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
415421
const std::string containerNodeName = containerNode->Name();
416422
if (containerNodeName == "size" || containerNodeName == "access" || containerNodeName == "other") {
417423
for (const tinyxml2::XMLElement *functionNode = containerNode->FirstChildElement(); functionNode; functionNode = functionNode->NextSiblingElement()) {
418-
if (std::string(functionNode->Name()) != "function")
419-
return Error(BAD_ELEMENT, functionNode->Name());
424+
if (std::string(functionNode->Name()) != "function") {
425+
unknown_elements.insert(functionNode->Name());
426+
continue;
427+
}
420428

421429
const char* const functionName = functionNode->Attribute("name");
422430
if (!functionName)
@@ -486,7 +494,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
486494
if (string)
487495
container.stdStringLike = std::string(string) == "std-like";
488496
} else
489-
return Error(BAD_ELEMENT, containerNodeName);
497+
unknown_elements.insert(containerNodeName);
490498
}
491499
}
492500

@@ -534,7 +542,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
534542
else if (typenodename == "const_ptr")
535543
type._const_ptr = true;
536544
else
537-
return Error(BAD_ELEMENT, typenodename);
545+
unknown_elements.insert(typenodename);
538546
}
539547
if (platform.empty()) {
540548
const PlatformType * const type_ptr = platform_type(type_name, "");
@@ -559,7 +567,16 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
559567
}
560568

561569
else
562-
return Error(BAD_ELEMENT, nodename);
570+
unknown_elements.insert(nodename);
571+
}
572+
if (!unknown_elements.empty()) {
573+
std::string str;
574+
for (std::set<std::string>::const_iterator i = unknown_elements.begin(); i != unknown_elements.end();) {
575+
str += *i;
576+
if (++i != unknown_elements.end())
577+
str += ", ";
578+
}
579+
return Error(UNKNOWN_ELEMENT, str);
563580
}
564581
return Error(OK);
565582
}

lib/library.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class CPPCHECKLIB Library {
4747
public:
4848
Library();
4949

50-
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 };
50+
enum ErrorCode { OK, FILE_NOT_FOUND, BAD_XML, UNKNOWN_ELEMENT, MISSING_ATTRIBUTE, BAD_ATTRIBUTE_VALUE, UNSUPPORTED_FORMAT, DUPLICATE_PLATFORM_TYPE, PLATFORM_TYPE_REDEFINED };
5151

5252
class Error {
5353
public:

0 commit comments

Comments
 (0)