Skip to content

Commit c7bc7a8

Browse files
authored
cleaned up handling of specifying multiple libraries at once (#6593)
1 parent eeb0126 commit c7bc7a8

File tree

7 files changed

+133
-17
lines changed

7 files changed

+133
-17
lines changed

cli/cmdlineparser.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -870,7 +870,14 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
870870

871871
// --library
872872
else if (std::strncmp(argv[i], "--library=", 10) == 0) {
873-
mSettings.libraries.emplace_back(argv[i] + 10);
873+
std::list<std::string> libs = splitString(argv[i] + 10, ',');
874+
for (auto& l : libs) {
875+
if (l.empty()) {
876+
mLogger.printError("empty library specified.");
877+
return Result::Fail;
878+
}
879+
mSettings.libraries.emplace_back(std::move(l));
880+
}
874881
}
875882

876883
// Set maximum number of #ifdef configurations to check

lib/library.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -184,23 +184,8 @@ static void gettokenlistfromvalid(const std::string& valid, bool cpp, TokenList&
184184

185185
Library::Error Library::load(const char exename[], const char path[], bool debug)
186186
{
187-
// TODO: remove handling of multiple libraries at once?
188187
if (std::strchr(path,',') != nullptr) {
189-
if (debug)
190-
std::cout << "handling multiple libraries '" + std::string(path) + "'" << std::endl;
191-
std::string p(path);
192-
for (;;) {
193-
const std::string::size_type pos = p.find(',');
194-
if (pos == std::string::npos)
195-
break;
196-
const Error &e = load(exename, p.substr(0,pos).c_str());
197-
if (e.errorcode != ErrorCode::OK)
198-
return e;
199-
p = p.substr(pos+1);
200-
}
201-
if (!p.empty())
202-
return load(exename, p.c_str());
203-
return Error();
188+
throw std::runtime_error("handling of multiple libraries not supported");
204189
}
205190

206191
const bool is_abs_path = Path::isAbsolute(path);

lib/utils.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include <algorithm>
2222
#include <cctype>
23+
#include <cstring>
2324
#include <iterator>
2425
#include <stack>
2526
#include <utility>
@@ -184,3 +185,21 @@ std::string replaceEscapeSequences(const std::string &source) {
184185
return result;
185186
}
186187

188+
189+
std::list<std::string> splitString(const std::string& str, char sep)
190+
{
191+
if (std::strchr(str.c_str(), sep) == nullptr)
192+
return {str};
193+
194+
std::list<std::string> l;
195+
std::string p(str);
196+
for (;;) {
197+
const std::string::size_type pos = p.find(sep);
198+
if (pos == std::string::npos)
199+
break;
200+
l.push_back(p.substr(0,pos));
201+
p = p.substr(pos+1);
202+
}
203+
l.push_back(std::move(p));
204+
return l;
205+
}

lib/utils.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <functional>
3131
#include <initializer_list>
3232
#include <limits>
33+
#include <list>
3334
#include <stdexcept>
3435
#include <string>
3536
#include <type_traits>
@@ -390,4 +391,12 @@ static inline T* empty_if_null(T* p)
390391
return p ? p : "";
391392
}
392393

394+
/**
395+
* Split string by given sperator.
396+
* @param str The string to split
397+
* @param sep The seperator
398+
* @return The list of seperate strings (including empty ones). The whole input string if no seperator found.
399+
*/
400+
CPPCHECKLIB std::list<std::string> splitString(const std::string& str, char sep);
401+
393402
#endif

test/cli/other_test.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,3 +1728,27 @@ def test_lib_lookup_nofile(tmpdir):
17281728
"looking for library '{}/cfg/gtk.cfg'".format(exepath),
17291729
'Checking {} ...'.format(test_file)
17301730
]
1731+
1732+
1733+
def test_lib_lookup_multi(tmpdir):
1734+
test_file = os.path.join(tmpdir, 'test.c')
1735+
with open(test_file, 'wt'):
1736+
pass
1737+
1738+
exitcode, stdout, _, exe = cppcheck_ex(['--library=posix,gnu', '--debug-lookup', test_file])
1739+
exepath = os.path.dirname(exe)
1740+
if sys.platform == 'win32':
1741+
exepath = exepath.replace('\\', '/')
1742+
assert exitcode == 0, stdout
1743+
lines = __remove_std_lookup_log(stdout.splitlines(), exepath)
1744+
assert lines == [
1745+
"looking for library 'posix'",
1746+
"looking for library 'posix.cfg'",
1747+
"looking for library '{}/posix.cfg'".format(exepath),
1748+
"looking for library '{}/cfg/posix.cfg'".format(exepath),
1749+
"looking for library 'gnu'",
1750+
"looking for library 'gnu.cfg'",
1751+
"looking for library '{}/gnu.cfg'".format(exepath),
1752+
"looking for library '{}/cfg/gnu.cfg'".format(exepath),
1753+
'Checking {} ...'.format(test_file)
1754+
]

test/testcmdlineparser.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ class TestCmdlineParser : public TestFixture {
364364
TEST_CASE(signedCharUnsignedChar);
365365
TEST_CASE(library);
366366
TEST_CASE(libraryMissing);
367+
TEST_CASE(libraryMultiple);
368+
TEST_CASE(libraryMultipleEmpty);
369+
TEST_CASE(libraryMultipleEmpty2);
367370
TEST_CASE(suppressXml);
368371
TEST_CASE(suppressXmlEmpty);
369372
TEST_CASE(suppressXmlMissing);
@@ -2447,6 +2450,30 @@ class TestCmdlineParser : public TestFixture {
24472450
ASSERT_EQUALS("cppcheck: Failed to load library configuration file 'posix2'. File not found\n", logger->str());
24482451
}
24492452

2453+
void libraryMultiple() {
2454+
REDIRECT;
2455+
const char * const argv[] = {"cppcheck", "--library=posix,gnu", "file.cpp"};
2456+
ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv));
2457+
ASSERT_EQUALS(2, settings->libraries.size());
2458+
auto it = settings->libraries.cbegin();
2459+
ASSERT_EQUALS("posix", *it++);
2460+
ASSERT_EQUALS("gnu", *it);
2461+
}
2462+
2463+
void libraryMultipleEmpty() {
2464+
REDIRECT;
2465+
const char * const argv[] = {"cppcheck", "--library=posix,,gnu", "file.cpp"};
2466+
ASSERT_EQUALS(false, parser->fillSettingsFromArgs(3, argv));
2467+
ASSERT_EQUALS("cppcheck: error: empty library specified.\n", logger->str());
2468+
}
2469+
2470+
void libraryMultipleEmpty2() {
2471+
REDIRECT;
2472+
const char * const argv[] = {"cppcheck", "--library=posix,gnu,", "file.cpp"};
2473+
ASSERT_EQUALS(false, parser->fillSettingsFromArgs(3, argv));
2474+
ASSERT_EQUALS("cppcheck: error: empty library specified.\n", logger->str());
2475+
}
2476+
24502477
void suppressXml() {
24512478
REDIRECT;
24522479
ScopedFile file("suppress.xml",

test/testutils.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class TestUtils : public TestFixture {
4141
TEST_CASE(trim);
4242
TEST_CASE(findAndReplace);
4343
TEST_CASE(replaceEscapeSequences);
44+
TEST_CASE(splitString);
4445
}
4546

4647
void isValidGlobPattern() const {
@@ -438,6 +439,50 @@ class TestUtils : public TestFixture {
438439
ASSERT_EQUALS("\\", ::replaceEscapeSequences("\\\\"));
439440
ASSERT_EQUALS("\"", ::replaceEscapeSequences("\\\""));
440441
}
442+
443+
void splitString() const {
444+
{
445+
const auto l = ::splitString("test", ',');
446+
ASSERT_EQUALS(1, l.size());
447+
ASSERT_EQUALS("test", *l.cbegin());
448+
}
449+
{
450+
const auto l = ::splitString("test,test", ';');
451+
ASSERT_EQUALS(1, l.size());
452+
ASSERT_EQUALS("test,test", *l.cbegin());
453+
}
454+
{
455+
const auto l = ::splitString("test,test", ',');
456+
ASSERT_EQUALS(2, l.size());
457+
auto it = l.cbegin();
458+
ASSERT_EQUALS("test", *it++);
459+
ASSERT_EQUALS("test", *it);
460+
}
461+
{
462+
const auto l = ::splitString("test,test,", ',');
463+
ASSERT_EQUALS(3, l.size());
464+
auto it = l.cbegin();
465+
ASSERT_EQUALS("test", *it++);
466+
ASSERT_EQUALS("test", *it++);
467+
ASSERT_EQUALS("", *it);
468+
}
469+
{
470+
const auto l = ::splitString("test,,test", ',');
471+
ASSERT_EQUALS(3, l.size());
472+
auto it = l.cbegin();
473+
ASSERT_EQUALS("test", *it++);
474+
ASSERT_EQUALS("", *it++);
475+
ASSERT_EQUALS("test", *it);
476+
}
477+
{
478+
const auto l = ::splitString(",test,test", ',');
479+
ASSERT_EQUALS(3, l.size());
480+
auto it = l.cbegin();
481+
ASSERT_EQUALS("", *it++);
482+
ASSERT_EQUALS("test", *it++);
483+
ASSERT_EQUALS("test", *it);
484+
}
485+
}
441486
};
442487

443488
REGISTER_TEST(TestUtils)

0 commit comments

Comments
 (0)