Skip to content

Commit e3dacd8

Browse files
authored
refs #14304/#14242 - fixed active checkers with UNUSEDFUNCTION_ONLY hack (#8005)
1 parent 7b1c3bb commit e3dacd8

File tree

4 files changed

+99
-20
lines changed

4 files changed

+99
-20
lines changed

cli/singleexecutor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ unsigned int SingleExecutor::check()
6767
reportStatus(c, mFileSettings.size(), c, mFileSettings.size());
6868
}
6969

70+
// TODO: CppCheckExecutor::check_internal() is also invoking the whole program analysis - is it run twice?
7071
if (mCppcheck.analyseWholeProgram())
7172
result++;
7273

lib/checkersreport.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,13 @@ void CheckersReport::countCheckers()
143143
++mAllCheckersCount;
144144
}
145145
if (mSettings.premiumArgs.find("misra-c-") != std::string::npos || mSettings.addons.count("misra")) {
146+
const bool doUnusedFunctionOnly = Settings::unusedFunctionOnly();
146147
for (const checkers::MisraInfo& info: checkers::misraC2012Rules) {
147148
const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
148-
const bool active = isMisraRuleActive(mActiveCheckers, rule);
149+
// this will return some rules as always active even if they are not in the active checkers.
150+
// this leads to a difference in the shown count and in the checkers stored in the builddir
151+
// TODO: fix this?
152+
const bool active = !doUnusedFunctionOnly && isMisraRuleActive(mActiveCheckers, rule);
149153
if (active)
150154
++mActiveCheckersCount;
151155
++mAllCheckersCount;

lib/cppcheck.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,7 +1495,7 @@ void CppCheck::executeAddons(const std::string& dumpFile, const FileWithDetails&
14951495

14961496
void CppCheck::executeAddons(const std::vector<std::string>& files, const std::string& file0)
14971497
{
1498-
if (mSettings.addons.empty() || files.empty())
1498+
if (mSettings.addons.empty() || files.empty() || Settings::unusedFunctionOnly())
14991499
return;
15001500

15011501
const bool isCtuInfo = endsWith(files[0], ".ctu-info");
@@ -1807,22 +1807,25 @@ void CppCheck::analyseClangTidy(const FileSettings &fileSettings)
18071807
bool CppCheck::analyseWholeProgram()
18081808
{
18091809
bool errors = false;
1810-
// Analyse the tokens
1811-
CTU::FileInfo ctu;
1812-
if (mSettings.useSingleJob() || !mSettings.buildDir.empty())
1813-
{
1814-
for (const Check::FileInfo *fi : mFileInfo) {
1815-
const auto *fi2 = dynamic_cast<const CTU::FileInfo *>(fi);
1816-
if (fi2) {
1817-
ctu.functionCalls.insert(ctu.functionCalls.end(), fi2->functionCalls.cbegin(), fi2->functionCalls.cend());
1818-
ctu.nestedCalls.insert(ctu.nestedCalls.end(), fi2->nestedCalls.cbegin(), fi2->nestedCalls.cend());
1810+
1811+
if (!Settings::unusedFunctionOnly()) {
1812+
// Analyse the tokens
1813+
CTU::FileInfo ctu;
1814+
if (mSettings.useSingleJob() || !mSettings.buildDir.empty())
1815+
{
1816+
for (const Check::FileInfo *fi : mFileInfo) {
1817+
const auto *fi2 = dynamic_cast<const CTU::FileInfo *>(fi);
1818+
if (fi2) {
1819+
ctu.functionCalls.insert(ctu.functionCalls.end(), fi2->functionCalls.cbegin(), fi2->functionCalls.cend());
1820+
ctu.nestedCalls.insert(ctu.nestedCalls.end(), fi2->nestedCalls.cbegin(), fi2->nestedCalls.cend());
1821+
}
18191822
}
18201823
}
1821-
}
18221824

1823-
// cppcheck-suppress shadowFunction - TODO: fix this
1824-
for (Check *check : Check::instances())
1825-
errors |= check->analyseWholeProgram(ctu, mFileInfo, mSettings, mErrorLogger); // TODO: ctu
1825+
// cppcheck-suppress shadowFunction - TODO: fix this
1826+
for (Check *check : Check::instances())
1827+
errors |= check->analyseWholeProgram(ctu, mFileInfo, mSettings, mErrorLogger); // TODO: ctu
1828+
}
18261829

18271830
if (mUnusedFunctionsCheck)
18281831
errors |= mUnusedFunctionsCheck->check(mSettings, mErrorLogger);
@@ -1832,9 +1835,16 @@ bool CppCheck::analyseWholeProgram()
18321835

18331836
unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings, const std::string& ctuInfo)
18341837
{
1835-
executeAddonsWholeProgram(files, fileSettings, ctuInfo);
18361838
if (mSettings.checks.isEnabled(Checks::unusedFunction))
18371839
CheckUnusedFunctions::analyseWholeProgram(mSettings, mErrorLogger, buildDir);
1840+
1841+
if (mUnusedFunctionsCheck)
1842+
mUnusedFunctionsCheck->check(mSettings, mErrorLogger);
1843+
1844+
if (Settings::unusedFunctionOnly())
1845+
return mLogger->exitcode();
1846+
1847+
executeAddonsWholeProgram(files, fileSettings, ctuInfo);
18381848
std::list<Check::FileInfo*> fileInfoList;
18391849
CTU::FileInfo ctuFileInfo;
18401850

@@ -1885,9 +1895,6 @@ unsigned int CppCheck::analyseWholeProgram(const std::string &buildDir, const st
18851895
for (Check *check : Check::instances())
18861896
check->analyseWholeProgram(ctuFileInfo, fileInfoList, mSettings, mErrorLogger);
18871897

1888-
if (mUnusedFunctionsCheck)
1889-
mUnusedFunctionsCheck->check(mSettings, mErrorLogger);
1890-
18911898
for (Check::FileInfo *fi : fileInfoList)
18921899
delete fi;
18931900

test/cli/other_test.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4051,4 +4051,71 @@ def test_no_valid_configuration_check_config(tmp_path):
40514051
assert stderr.splitlines() == [
40524052
'{}:1:2: error: No header in #include [syntaxError]'.format(test_file),
40534053
'{}:1:2: error: No header in #include [syntaxError]'.format(test_file)
4054-
]
4054+
]
4055+
4056+
4057+
def __test_active_checkers(tmp_path, active_cnt, total_cnt, use_misra=False, use_unusedfunction_only=False, checkers_exp=None):
4058+
test_file = tmp_path / 'test.c'
4059+
with open(test_file, 'w') as f:
4060+
f.write('int i;')
4061+
4062+
build_dir = None
4063+
if checkers_exp is not None:
4064+
build_dir = tmp_path / 'b1'
4065+
os.makedirs(build_dir)
4066+
4067+
args = [
4068+
'-q',
4069+
'--enable=information',
4070+
'-j1',
4071+
str(test_file)
4072+
]
4073+
4074+
if use_misra:
4075+
args += ['--addon=misra']
4076+
if build_dir:
4077+
args += ['--cppcheck-build-dir={}'.format(build_dir)]
4078+
else:
4079+
args += ['--no-cppcheck-build-dir']
4080+
4081+
env = {}
4082+
if use_unusedfunction_only:
4083+
env = {'UNUSEDFUNCTION_ONLY': '1'}
4084+
args += ['--enable=unusedFunction']
4085+
exitcode, stdout, stderr, _ = cppcheck_ex(args, remove_checkers_report=False, env=env)
4086+
assert exitcode == 0, stdout
4087+
assert stdout.splitlines() == []
4088+
assert stderr.splitlines() == [
4089+
f'nofile:0:0: information: Active checkers: {active_cnt}/{total_cnt} (use --checkers-report=<filename> to see details) [checkersReport]',
4090+
'' # TODO: get rid of extra newline
4091+
]
4092+
4093+
if build_dir:
4094+
checkers_file = build_dir / 'checkers.txt'
4095+
with open(checkers_file, 'r') as f:
4096+
checkers = f.read().splitlines()
4097+
4098+
assert checkers == checkers_exp
4099+
assert len(checkers) == active_cnt
4100+
4101+
4102+
def test_active_unusedfunction_only(tmp_path):
4103+
__test_active_checkers(tmp_path, 1, 966, use_unusedfunction_only=True)
4104+
4105+
4106+
def test_active_unusedfunction_only_builddir(tmp_path):
4107+
checkers_exp = [
4108+
'CheckUnusedFunctions::check'
4109+
]
4110+
__test_active_checkers(tmp_path, 1, 966, use_unusedfunction_only=True, checkers_exp=checkers_exp)
4111+
4112+
4113+
def test_active_unusedfunction_only_misra(tmp_path):
4114+
__test_active_checkers(tmp_path, 1, 1166, use_unusedfunction_only=True, use_misra=True)
4115+
4116+
4117+
def test_active_unusedfunction_only_misra_builddir(tmp_path):
4118+
checkers_exp = [
4119+
'CheckUnusedFunctions::check'
4120+
]
4121+
__test_active_checkers(tmp_path, 1, 1166, use_unusedfunction_only=True, use_misra=True, checkers_exp=checkers_exp)

0 commit comments

Comments
 (0)