Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,12 @@ static void valueFlowEnumValue(SymbolDatabase & symboldatabase, const Settings &
}
}

// trampoline to generate unique timer results entry
static void valueFlowEnumValueEarly(SymbolDatabase & symboldatabase, const Settings & settings)
{
valueFlowEnumValue(symboldatabase, settings);
}

static void valueFlowGlobalConstVar(TokenList& tokenList, const Settings& settings)
{
// Get variable values...
Expand Down Expand Up @@ -7200,7 +7206,7 @@ struct ValueFlowPassRunner {
bool run_once(std::initializer_list<ValuePtr<ValueFlowPass>> passes) const
{
return std::any_of(passes.begin(), passes.end(), [&](const ValuePtr<ValueFlowPass>& pass) {
return run(pass);
return run(pass, 0);
});
}

Expand All @@ -7210,10 +7216,11 @@ struct ValueFlowPassRunner {
std::size_t n = state.settings.vfOptions.maxIterations;
while (n > 0 && values != getTotalValues()) {
values = getTotalValues();
const std::string passnum = std::to_string(state.settings.vfOptions.maxIterations - n + 1);
const std::size_t passnum = state.settings.vfOptions.maxIterations - n + 1;
const std::string passnum_s = std::to_string(passnum);
if (std::any_of(passes.begin(), passes.end(), [&](const ValuePtr<ValueFlowPass>& pass) {
ProgressReporter progressReporter(state.errorLogger, state.settings.reportProgress >= 0, state.tokenlist.getSourceFilePath(), std::string("ValueFlow::") + pass->name() + (' ' + passnum));
return run(pass);
ProgressReporter progressReporter(state.errorLogger, state.settings.reportProgress >= 0, state.tokenlist.getSourceFilePath(), std::string("ValueFlow::") + pass->name() + (' ' + passnum_s));
return run(pass, passnum);
}))
return true;
--n;
Expand All @@ -7233,7 +7240,7 @@ struct ValueFlowPassRunner {
return false;
}

bool run(const ValuePtr<ValueFlowPass>& pass) const
bool run(const ValuePtr<ValueFlowPass>& pass, std::size_t it) const
{
auto start = Clock::now();
if (start > stop) {
Expand All @@ -7243,7 +7250,12 @@ struct ValueFlowPassRunner {
if (!state.tokenlist.isCPP() && pass->cpp())
return false;
if (timerResults) {
Timer t(pass->name(), state.settings.showtime, timerResults);
std::string name = pass->name();
if (it > 0) {
name += ' ';
name += std::to_string(it);
}
Timer t(name, state.settings.showtime, timerResults);
pass->run(state);
} else {
pass->run(state);
Expand Down Expand Up @@ -7375,7 +7387,7 @@ void ValueFlow::setValues(TokenList& tokenlist,

ValueFlowPassRunner runner{ValueFlowState{tokenlist, symboldatabase, errorLogger, settings}, timerResults};
runner.run_once({
VFA(valueFlowEnumValue(symboldatabase, settings)),
VFA(valueFlowEnumValueEarly(symboldatabase, settings)),
VFA(valueFlowNumber(tokenlist, settings)),
VFA(valueFlowString(tokenlist, settings)),
VFA(valueFlowTypeTraits(tokenlist, settings)),
Expand Down
58 changes: 48 additions & 10 deletions test/cli/other_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -954,8 +954,11 @@ def test_unused_function_include(tmpdir):
__test_unused_function_include(tmpdir, [])


# TODO: test with clang-tidy
# TODO: test with --addon
# TODO: test with FileSettings
# TODO: test with multiple files
def __test_showtime(tmp_path, showtime, exp_len, exp_last, extra_args=None):
def __test_showtime(tmp_path, showtime, exp_res, exp_last, extra_args=None):
test_file = tmp_path / 'test.cpp'
with open(test_file, 'wt') as f:
f.write(
Expand All @@ -979,37 +982,40 @@ def __test_showtime(tmp_path, showtime, exp_len, exp_last, extra_args=None):
exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0
lines = stdout.splitlines()
exp_len = exp_res
if exp_res:
exp_len += 1 # empty line at the beginning - only added when individual results exist
if 'cppcheck internal API usage' in stdout:
exp_len += 1
exp_len += 1 # last line
assert len(lines) == exp_len
idx_last = exp_len-1
if idx_last:
if exp_res:
assert lines[0] == ''
for i in range(1, idx_last):
for i in range(1, exp_res):
assert 'avg.' in lines[i]
assert lines[idx_last].startswith(exp_last)
assert lines[exp_len-1].startswith(exp_last)
assert stderr == ''


def test_showtime_top5_file(tmp_path):
__test_showtime(tmp_path, 'top5_file', 7, 'Check time: ')
__test_showtime(tmp_path, 'top5_file', 5, 'Check time: ')


# TODO: remove extra args when --executor=process works works
def test_showtime_top5_summary(tmp_path):
__test_showtime(tmp_path, 'top5_summary', 7, 'Overall time: ', ['-j1'])
__test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', ['-j1'])


# TODO: remove when --executor=process works works
def test_showtime_top5_summary_j_thread(tmp_path):
__test_showtime(tmp_path, 'top5_summary', 7, 'Overall time: ', ['-j2', '--executor=thread'])
__test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', ['-j2', '--executor=thread'])


# TODO: remove override when fixed
@pytest.mark.skipif(sys.platform == 'win32', reason="requires ProcessExecutor")
@pytest.mark.xfail(strict=True) # TODO: need to transfer the timer results to parent process - see #4452
def test_showtime_top5_summary_j_process(tmp_path):
__test_showtime(tmp_path, 'top5_summary', 7, 'Overall time: ', ['-j2', '--executor=process'])
__test_showtime(tmp_path, 'top5_summary', 5, 'Overall time: ', ['-j2', '--executor=process'])


def test_showtime_file(tmp_path):
Expand All @@ -1034,7 +1040,39 @@ def test_showtime_summary_j_process(tmp_path):


def test_showtime_file_total(tmp_path):
__test_showtime(tmp_path, 'file-total', 1, 'Check time: ')
__test_showtime(tmp_path, 'file-total', 0, 'Check time: ')


def test_showtime_unique(tmp_path):
test_file = tmp_path / 'test.cpp'
with open(test_file, 'wt') as f:
f.write(
"""
void f()
{
(void)(*((int*)0)); // cppcheck-suppress nullPointer
}
""")

args = [
'--showtime=summary',
'--quiet',
'--inline-suppr',
str(test_file)
]

exitcode, stdout, stderr = cppcheck(args)
assert exitcode == 0
multi_res = []
for line in stdout.splitlines():
# TODO: remove when we no longer emit empty line
if not line:
continue
if any(i in line for i in ['1 result(s)', 'Overall time:']):
continue
multi_res.append(line)
assert multi_res == []
assert stderr == ''


def test_missing_addon(tmpdir):
Expand Down
Loading