Skip to content
Draft
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
23 changes: 2 additions & 21 deletions cli/cppcheckexecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,33 +385,14 @@ bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, con

bool err = false;

for (auto i = files.cbegin(); i != files.cend(); ++i) {
const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), settings.unmatchedSuppressionFilters);
err |= reportErrorsFn(i->spath(), i->fsFileId(), errors);
}

for (auto i = fileSettings.cbegin(); i != fileSettings.cend(); ++i) {
const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), settings.unmatchedSuppressionFilters);
err |= reportErrorsFn(i->file.spath(), i->file.fsFileId(), errors);
}

if (settings.inlineSuppressions) {
const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), settings.unmatchedSuppressionFilters);
for (const auto& errmsg : errors) {
std::string sourcefile;
if (!errmsg.callStack.empty())
sourcefile = errmsg.callStack.cbegin()->getfile(false); // TODO: simplify path?
err |= reportErrorsFn(sourcefile, 0, {errmsg});
}
}

const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), settings.unmatchedSuppressionFilters);
const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedSuppressions(), settings.unmatchedSuppressionFilters);
for (const auto& errmsg : errors) {
std::string sourcefile;
if (!errmsg.callStack.empty())
sourcefile = errmsg.callStack.cbegin()->getfile(false); // TODO: simplify path?
err |= reportErrorsFn(sourcefile, 0, {errmsg});
}

return err;
}

Expand Down
15 changes: 15 additions & 0 deletions lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,21 @@ unsigned int CppCheck::checkInternal(const FileWithDetails& file, const std::str
mSuppressions.nomsg.markUnmatchedInlineSuppressionsAsChecked(tokenizer.list);
}

// TODO: handle differently?
// dummy call to make sure included files are being flagged as checked in case isSuppressed() is never called
for (auto f : tokenizer.list.getFiles())
{
f = Path::simplifyPath(f); // TODO: necessary?

// skip the file which is being analyzed
if (f == file.spath())
continue;

// the empty ID is intentional for now - although it should not be allowed
ErrorMessage msg({}, f, Severity::information, "", "", Certainty::normal);
(void)mSuppressions.nomsg.isSuppressed(SuppressionList::ErrorMessage::fromErrorMessage(msg, {}), true);
}

// Skip if we already met the same simplified token list
if (maxConfigs > 1) {
const std::size_t hash = tokenizer.list.calculateHash();
Expand Down
45 changes: 1 addition & 44 deletions lib/suppressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -555,32 +555,7 @@ void SuppressionList::dump(std::ostream & out, const std::string& filePath) cons
out << " </suppressions>" << std::endl;
}

std::list<SuppressionList::Suppression> SuppressionList::getUnmatchedLocalSuppressions(const FileWithDetails &file) const
{
std::lock_guard<std::mutex> lg(mSuppressionsSync);

std::list<Suppression> result;
for (const Suppression &s : mSuppressions) {
if (s.isInline)
continue;
if (s.matched)
continue;
if ((s.lineNumber != Suppression::NO_LINE) && !s.checked)
continue;
if (s.type == SuppressionList::Type::macro)
continue;
if (s.hash > 0)
continue;
if (s.errorId == ID_CHECKERSREPORT)
continue;
if (!s.isLocal() || !PathMatch::match(s.fileName, file.spath()))
continue;
result.push_back(s);
}
return result;
}

std::list<SuppressionList::Suppression> SuppressionList::getUnmatchedGlobalSuppressions() const
std::list<SuppressionList::Suppression> SuppressionList::getUnmatchedSuppressions() const
{
std::lock_guard<std::mutex> lg(mSuppressionsSync);

Expand All @@ -603,24 +578,6 @@ std::list<SuppressionList::Suppression> SuppressionList::getUnmatchedGlobalSuppr
return result;
}

std::list<SuppressionList::Suppression> SuppressionList::getUnmatchedInlineSuppressions() const
{
std::list<SuppressionList::Suppression> result;
for (const SuppressionList::Suppression &s : SuppressionList::mSuppressions) {
if (!s.isInline)
continue;
// TODO: remove this and markUnmatchedInlineSuppressionsAsChecked()?
if (!s.checked)
continue;
if (s.matched)
continue;
if (s.hash > 0)
continue;
result.push_back(s);
}
return result;
}

std::list<SuppressionList::Suppression> SuppressionList::getSuppressions() const
{
std::lock_guard<std::mutex> lg(mSuppressionsSync);
Expand Down
16 changes: 2 additions & 14 deletions lib/suppressions.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,22 +259,10 @@ class CPPCHECKLIB SuppressionList {
void dump(std::ostream &out, const std::string& filePath = {}) const;

/**
* @brief Returns list of unmatched local (per-file) suppressions.
* @brief Returns list of unmatched suppressions.
* @return list of unmatched suppressions
*/
std::list<Suppression> getUnmatchedLocalSuppressions(const FileWithDetails &file) const;

/**
* @brief Returns list of unmatched global (glob pattern) suppressions.
* @return list of unmatched suppressions
*/
std::list<Suppression> getUnmatchedGlobalSuppressions() const;

/**
* @brief Returns list of unmatched inline suppressions.
* @return list of unmatched suppressions
*/
std::list<Suppression> getUnmatchedInlineSuppressions() const;
std::list<Suppression> getUnmatchedSuppressions() const;

/**
* @brief Returns list of all suppressions.
Expand Down
23 changes: 23 additions & 0 deletions test/cli/other_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4749,4 +4749,27 @@ def test_ipc_inline_suppressions(tmp_path):
stdout_lines = stdout.splitlines()
stdout_lines.sort()
assert stdout_lines == stdout_exp
assert stderr.splitlines() == []


def test_suppression_unmatched_header(tmp_path):
test_file = tmp_path / 'test.c'
with open(test_file, "w") as f:
f.write('#include "inc.h"')

inc_file = tmp_path / 'inc.h'
with open(inc_file, "w") as f:
f.write('')

args = [
'-q',
'--template=simple',
'--enabled=information',
'--suppress=id:inc.h',
str(test_file)
]

exitcode, stdout, stderr = cppcheck(args,)
assert exitcode == 0
assert stdout == ''
assert stderr.splitlines() == []