Skip to content

Commit ceca6a1

Browse files
authored
fixed #13518 - added command-line option --{no-}check-unused-templates (danmar#7291)
1 parent 6c57803 commit ceca6a1

File tree

4 files changed

+179
-4
lines changed

4 files changed

+179
-4
lines changed

cli/cmdlineparser.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
572572
mSettings.checkLibrary = true;
573573
}
574574

575+
else if (std::strcmp(argv[i], "--check-unused-templates") == 0)
576+
mSettings.checkUnusedTemplates = true;
577+
575578
else if (std::strncmp(argv[i], "--check-version=", 16) == 0) {
576579
if (!loadCppcheckCfg())
577580
return Result::Fail;
@@ -1007,6 +1010,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
10071010
else if (std::strcmp(argv[i], "--no-check-headers") == 0)
10081011
mSettings.checkHeaders = false;
10091012

1013+
else if (std::strcmp(argv[i], "--no-check-unused-templates") == 0)
1014+
mSettings.checkUnusedTemplates = false;
1015+
10101016
// undocumented option for usage in Python tests to indicate that no build dir should be injected
10111017
else if (std::strcmp(argv[i], "--no-cppcheck-build-dir") == 0) {
10121018
mSettings.buildDir.clear();

lib/settings.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ class CPPCHECKLIB WARN_UNUSED Settings {
152152
std::set<std::string> checkUnknownFunctionReturn; // TODO: move to Library?
153153

154154
/** Check unused/uninstantiated templates */
155-
bool checkUnusedTemplates = true; // TODO: CLI
155+
bool checkUnusedTemplates = true;
156156

157157
/** Use Clang */
158158
bool clang{};

test/cli/other_test.py

Lines changed: 148 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3166,7 +3166,6 @@ def test_dir_ignore(tmp_path):
31663166
assert_cppcheck(args, ec_exp=0, err_exp=[], out_exp=out_lines, cwd=str(tmp_path))
31673167

31683168

3169-
31703169
def test_check_headers(tmp_path):
31713170
test_file_h = tmp_path / 'test.h'
31723171
with open(test_file_h, 'wt') as f:
@@ -3199,7 +3198,6 @@ def test_check_headers(tmp_path):
31993198
assert stderr.splitlines() == [] # no error since the header is not checked
32003199

32013200

3202-
32033201
def test_unique_error(tmp_path): # #6366
32043202
test_file = tmp_path / 'test.c'
32053203
with open(test_file, 'wt') as f:
@@ -3224,4 +3222,151 @@ def test_unique_error(tmp_path): # #6366
32243222
assert stderr.splitlines() == [
32253223
"{}:4:13: error: Array 'm[9]' accessed at index 9, which is out of bounds. [arrayIndexOutOfBounds]".format(test_file),
32263224
"{}:4:21: error: Array 'm[9]' accessed at index 9, which is out of bounds. [arrayIndexOutOfBounds]".format(test_file)
3227-
]
3225+
]
3226+
3227+
3228+
def test_check_unused_templates_class(tmp_path):
3229+
test_file_h = tmp_path / 'test.h'
3230+
with open(test_file_h, 'wt') as f:
3231+
f.write(
3232+
"""template<class T>
3233+
class HdrCl1
3234+
{
3235+
HdrCl1()
3236+
{
3237+
(void)(*((int*)0));
3238+
}
3239+
};
3240+
3241+
template<typename T>
3242+
class HdrCl2
3243+
{
3244+
HdrCl2()
3245+
{
3246+
(void)(*((int*)0));
3247+
}
3248+
};
3249+
3250+
template<class T>
3251+
struct HdrSt1
3252+
{
3253+
HdrSt1()
3254+
{
3255+
(void)(*((int*)0));
3256+
}
3257+
};
3258+
3259+
template<typename T>
3260+
struct HdrSt2
3261+
{
3262+
HdrSt2()
3263+
{
3264+
(void)(*((int*)0));
3265+
}
3266+
};
3267+
""")
3268+
3269+
test_file = tmp_path / 'test.cpp'
3270+
with open(test_file, 'wt') as f:
3271+
f.write(
3272+
"""#include "test.h"
3273+
3274+
template<class T>
3275+
class Cl1
3276+
{
3277+
CL1()
3278+
{
3279+
(void)(*((int*)0));
3280+
}
3281+
};
3282+
3283+
template<typename T>
3284+
class Cl2
3285+
{
3286+
Cl2()
3287+
{
3288+
(void)(*((int*)0));
3289+
}
3290+
};
3291+
3292+
template<class T>
3293+
struct St1
3294+
{
3295+
St1()
3296+
{
3297+
(void)(*((int*)0));
3298+
}
3299+
};
3300+
3301+
template<typename T>
3302+
struct St2
3303+
{
3304+
St2()
3305+
{
3306+
(void)(*((int*)0));
3307+
}
3308+
};
3309+
3310+
void f() {}
3311+
""")
3312+
3313+
args = [
3314+
'-q',
3315+
'--template=simple',
3316+
'--no-check-unused-templates',
3317+
str(test_file)
3318+
]
3319+
exitcode, stdout, stderr = cppcheck(args)
3320+
assert exitcode == 0, stdout
3321+
assert stdout.splitlines() == []
3322+
assert stderr.splitlines() == [] # no error since the unused templates are not being checked
3323+
3324+
3325+
@pytest.mark.xfail(strict=True) # TODO: only the first unused templated function is not being checked
3326+
def test_check_unused_templates_func(tmp_path): # #13714
3327+
test_file_h = tmp_path / 'test.h'
3328+
with open(test_file_h, 'wt') as f:
3329+
f.write(
3330+
"""template<class T>
3331+
void f_t_hdr_1()
3332+
{
3333+
(void)(*((int*)0));
3334+
}
3335+
3336+
template<typename T>
3337+
void f_t_hdr_2()
3338+
{
3339+
(void)(*((int*)0));
3340+
}
3341+
""")
3342+
3343+
test_file = tmp_path / 'test.cpp'
3344+
with open(test_file, 'wt') as f:
3345+
f.write(
3346+
"""#include "test.h"
3347+
3348+
template<class T>
3349+
void f_t_1()
3350+
{
3351+
(void)(*((int*)0));
3352+
}
3353+
3354+
template<typename T>
3355+
void f_t_2()
3356+
{
3357+
(void)(*((int*)0));
3358+
}
3359+
3360+
void f() {}
3361+
""")
3362+
3363+
args = [
3364+
'-q',
3365+
'--template=simple',
3366+
'--no-check-unused-templates',
3367+
str(test_file)
3368+
]
3369+
exitcode, stdout, stderr = cppcheck(args)
3370+
assert exitcode == 0, stdout
3371+
assert stdout.splitlines() == []
3372+
assert stderr.splitlines() == [] # no error since the unused templates are not being checked

test/testcmdlineparser.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,9 @@ class TestCmdlineParser : public TestFixture {
445445
TEST_CASE(noCheckHeaders);
446446
TEST_CASE(noCheckHeaders2);
447447
TEST_CASE(filesdir);
448+
TEST_CASE(checkUnusedTemplates);
449+
TEST_CASE(noCheckUnusedTemplates);
450+
TEST_CASE(noCheckUnusedTemplates);
448451

449452
TEST_CASE(ignorepaths1);
450453
TEST_CASE(ignorepaths2);
@@ -3024,6 +3027,27 @@ class TestCmdlineParser : public TestFixture {
30243027
#endif
30253028
}
30263029

3030+
void checkUnusedTemplates() {
3031+
REDIRECT;
3032+
const char * const argv[] = {"cppcheck", "--check-unused-templates", "file.cpp"};
3033+
ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv));
3034+
ASSERT_EQUALS(true, settings->checkUnusedTemplates);
3035+
}
3036+
3037+
void noCheckUnusedTemplates() {
3038+
REDIRECT;
3039+
const char * const argv[] = {"cppcheck", "--no-check-unused-templates", "file.cpp"};
3040+
ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(3, argv));
3041+
ASSERT_EQUALS(false, settings->checkUnusedTemplates);
3042+
}
3043+
3044+
void noCheckUnusedTemplates2() {
3045+
REDIRECT;
3046+
const char * const argv[] = {"cppcheck", "--check-unused-templates", "--no-check-unused-templates", "file.cpp"};
3047+
ASSERT_EQUALS_ENUM(CmdLineParser::Result::Success, parser->parseFromArgs(4, argv));
3048+
ASSERT_EQUALS(false, settings->checkUnusedTemplates);
3049+
}
3050+
30273051
void ignorepaths1() {
30283052
REDIRECT;
30293053
const char * const argv[] = {"cppcheck", "-isrc", "file.cpp"};

0 commit comments

Comments
 (0)