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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ $(libcppdir)/standards.o: lib/standards.cpp externals/simplecpp/simplecpp.h lib/
$(libcppdir)/summaries.o: lib/summaries.cpp lib/addoninfo.h lib/analyzerinfo.h lib/checkers.h lib/config.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/summaries.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp

$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(libcppdir)/suppressions.o: lib/suppressions.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/pathmatch.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h lib/xml.h
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp

$(libcppdir)/templatesimplifier.o: lib/templatesimplifier.cpp lib/addoninfo.h lib/checkers.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h
Expand Down
6 changes: 5 additions & 1 deletion cli/cppcheckexecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,11 @@ static bool reportUnmatchedSuppressions(const std::list<SuppressionList::Suppres
if (!s.fileName.empty()) {
callStack.emplace_back(s.fileName, s.lineNumber, 0);
}
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal));
if (s.isPolyspace) {
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched polyspace suppression: " + s.errorId, "unmatchedPolyspaceSuppression", Certainty::normal));
} else {
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal));
}
Comment on lines +332 to +336
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm.. we can make sure that only the id is different;

Suggested change
if (s.isPolyspace) {
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched polyspace suppression: " + s.errorId, "unmatchedPolyspaceSuppression", Certainty::normal));
} else {
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal));
}
const std::string unmatchSuppressionId = s.isPolyspace ? "unmatchedPolyspaceSuppression" : "unmatchedSuppression";
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, unmatchedSuppression, Certainty::normal));

err = true;
}
return err;
Expand Down
9 changes: 9 additions & 0 deletions lib/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,19 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett

bool onlyComments = true;

polyspace::Parser polyspaceParser(settings);

for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) {
if (!tok->comment) {
onlyComments = false;
continue;
}

if (polyspace::isPolyspaceComment(tok->str())) {
polyspaceParser.parse(tok->str(), tok->location.line, tokens.file(tok->location));
continue;
}

std::list<SuppressionList::Suppression> inlineSuppressions;
if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad))
continue;
Expand Down Expand Up @@ -310,6 +317,8 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
for (const SuppressionList::Suppression & suppr: inlineSuppressionsBlockBegin)
// cppcheck-suppress useStlAlgorithm
bad.emplace_back(suppr.fileName, suppr.lineNumber, 0, "Suppress Begin: No matching end"); // TODO: set column

polyspaceParser.collect(suppressions);
}

void Preprocessor::inlineSuppressions(SuppressionList &suppressions)
Expand Down
280 changes: 280 additions & 0 deletions lib/suppressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "token.h"
#include "tokenize.h"
#include "tokenlist.h"
#include "settings.h"

#include <algorithm>
#include <cctype> // std::isdigit, std::isalnum, etc
Expand Down Expand Up @@ -647,3 +648,282 @@ std::string SuppressionList::Suppression::toString() const
}
return s;
}

polyspace::Parser::Parser(const Settings &settings)
{
const auto matchArg = [&](const std::string &arg) {
const std::string args = settings.premiumArgs;
const std::string::size_type pos = args.find(arg);

if (pos == std::string::npos)
return false;

if (pos > 0 && args[pos - 1] != ' ')
return false;

return pos == args.size() - arg.size() || args[pos + arg.size()] == ' ';
};

if (settings.addons.count("misra") != 0) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is false if --addon=misra.json is used. I think it's more reliable to check if Settings::addonInfo contains an misra entry.

mFamilyMap["MISRA-C3"] = "misra-c2012-";
mFamilyMap["MISRA2012"] = "misra-c2012-";
}

if (matchArg("--misra-c-2012")) {
mFamilyMap["MISRA-C3"] = "premium-misra-c-2012-";
mFamilyMap["MISRA2012"] = "premium-misra-c-2012-";
}

if (matchArg("--misra-c-2023"))
mFamilyMap["MISRA-C-2023"] = "premium-misra-c-2023-";

if (matchArg("--misra-cpp-2008") || matchArg("--misra-c++-2008"))
mFamilyMap["MISRA-CPP"] = "premium-misra-cpp-2008-";

if (matchArg("--misra-cpp-2023") || matchArg("--misra-c++-2023"))
mFamilyMap["MISRA-CPP-2023"] = "premium-misra-cpp-2023-";

if (matchArg("--cert-c") || matchArg("--cert-c-2016"))
mFamilyMap["CERT-C"] = "premium-cert-c-";

if (matchArg("--cert-cpp") || matchArg("--cert-c++") ||
matchArg("--cert-cpp-2016") || matchArg("--cert-c++-2016"))
mFamilyMap["CERT-CPP"] = "premium-cert-cpp-";

if (matchArg("--autosar"))
mFamilyMap["AUTOSAR-CPP14"] = "premium-autosar-";
}

std::string polyspace::Parser::peekToken()
{
if (!mHasPeeked) {
mPeeked = nextToken();
mHasPeeked = true;
}
return mPeeked;
}

std::string polyspace::Parser::nextToken()
{
if (mHasPeeked) {
mHasPeeked = false;
return mPeeked;
}

if (mComment.compare(0, 2, "/*") == 0 || mComment.compare(0, 2, "//") == 0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks suspicious. do you expect "//" inside a comment also? not just at the start.
should // inside a comment be silently skipped.

mComment = mComment.substr(2);

std::string::size_type pos = 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mComment can be empty now can't it?

while (mComment[pos] == ' ') {
pos++;
if (pos == mComment.size()) {
mComment = "";
return "";
}
}

if (mComment.compare(0, 2, "*/") == 0) {
mComment = "";
return "";
}

if (mComment[pos] == ':') {
mComment = mComment.substr(pos + 1);
return ":";
}

if (mComment[pos] == ',') {
mComment = mComment.substr(pos + 1);
return ",";
}

const char *stopChars;
std::string::size_type skip;
switch (mComment[pos]) {
case '\"':
stopChars = "\"";
skip = 1;
break;
case '[':
stopChars = "]";
skip = 1;
break;
default:
stopChars = " :,";
skip = 0;
break;
}

const std::string::size_type start = pos;
pos += skip;

if (pos == mComment.size()) {
mComment = "";
return "";
}

while (std::strchr(stopChars, mComment[pos]) == nullptr) {
pos++;
if (pos == mComment.size())
break;
}

if (pos == mComment.size())
skip = 0;

const std::string token = mComment.substr(start, pos - start + skip);
mComment = mComment.substr(pos + skip);

return token;
}

void polyspace::Parser::finishSuppression()
{
Suppression suppr = { mFamily, mResultName, mFilename, 0, 0 };

switch (mKind) {
case CommentKind::Regular:
{
suppr.lineBegin = mLine;
suppr.lineEnd = mLine + mRange;
mDone.push_back(suppr);
return;
}
case CommentKind::Begin:
{
suppr.lineBegin = mLine;
mStarted.push_back(suppr);
return;
}
case CommentKind::End:
{
auto it = std::find_if(
mStarted.begin(),
mStarted.end(),
[&] (const Suppression &other) {
return suppr.matches(other);
}
);

if (it == mStarted.end())
return;

suppr.lineBegin = it->lineBegin;
suppr.lineEnd = mLine;
mStarted.erase(it);
mDone.push_back(suppr);
return;
}
}
}

bool polyspace::Parser::parseEntry()
{
mFamily = nextToken();
if (mFamily.empty())
return false;

if (nextToken() != ":")
return false;

// Parse result name, multiple names may be separated by commas
while (!mComment.empty()) {
mResultName = nextToken();
if (mResultName.empty())
return false;

finishSuppression();

if (peekToken() == ",") {
(void) nextToken();
continue;
}

break;
}

// Skip status and severity
if (!peekToken().empty() && mPeeked[0] == '[')
(void) nextToken();

return true;
}

void polyspace::Parser::collect(SuppressionList &suppressions) const
{
for (const auto &polyspaceSuppr : mDone) {
const auto it = mFamilyMap.find(polyspaceSuppr.family);
if (it == mFamilyMap.cend())
continue;

SuppressionList::Suppression suppr;
suppr.errorId = it->second + polyspaceSuppr.resultName;
suppr.isInline = true;
suppr.isPolyspace = true;
suppr.fileName = polyspaceSuppr.filename;

suppr.lineNumber = polyspaceSuppr.lineBegin;
if (polyspaceSuppr.lineBegin == polyspaceSuppr.lineEnd) {
suppr.type = SuppressionList::Type::unique;
} else {
suppr.type = SuppressionList::Type::block;
suppr.lineBegin = polyspaceSuppr.lineBegin;
suppr.lineEnd = polyspaceSuppr.lineEnd;
}

suppressions.addSuppression(std::move(suppr));
}
}

void polyspace::Parser::parse(const std::string &comment, int line, const std::string &filename)
{
mComment = comment;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (mFamilyMap.empty())
    return;

mLine = line;
mFilename = filename;
mHasPeeked = false;

while (true) {
const std::string kindStr = nextToken();
if (kindStr.empty())
return;

if (kindStr == "polyspace") mKind = CommentKind::Regular;
else if (kindStr == "polyspace-begin") mKind = CommentKind::Begin;
else if (kindStr == "polyspace-end") mKind = CommentKind::End;
else return;

mRange = 0;
if (peekToken()[0] == '+') {
try { mRange = std::stoi(mPeeked.substr(1)); } catch (...) { return; }
(void) nextToken();
}

while (parseEntry()) {
if (peekToken().empty() || mPeeked[0] == '\"')
break;
}

if (!peekToken().empty() && mPeeked[0] == '\"') {
(void) nextToken();
if (peekToken().empty())
return;
continue;
}

break;
}
}

bool polyspace::isPolyspaceComment(const std::string &comment)
{
const std::string polyspace = "polyspace";
const std::string::size_type pos = comment.find_first_not_of("/* ");
if (pos == std::string::npos)
return false;
return comment.compare(pos, polyspace.size(), polyspace, 0, polyspace.size()) == 0;
}

bool polyspace::Suppression::matches(const polyspace::Suppression &other) const
{
return family == other.family && resultName == other.resultName;
}
Loading
Loading