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
3 changes: 2 additions & 1 deletion cli/cppcheckexecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,8 @@ 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));
const std::string unmatchedSuppressionId = s.isPolyspace ? "unmatchedPolyspaceSuppression" : "unmatchedSuppression";
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, unmatchedSuppressionId, 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
286 changes: 286 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,288 @@ std::string SuppressionList::Suppression::toString() const
}
return s;
}

polyspace::Parser::Parser(const Settings &settings)
{
const auto it = std::find_if(settings.addonInfos.cbegin(),
settings.addonInfos.cend(),
[] (const AddonInfo &info) {
return info.name == "misra";
});

if (it != settings.addonInfos.cend()) {
mFamilyMap["MISRA-C3"] = "misra-c2012-";
mFamilyMap["MISRA2012"] = "misra-c2012-";
}

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 (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;
}

std::string::size_type pos = 0;
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)
{
if (mFamilyMap.empty())
return;

mComment = comment.substr(2);
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