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
35 changes: 21 additions & 14 deletions lib/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,27 +200,33 @@ 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;
}

std::list<SuppressionList::Suppression> inlineSuppressions;
if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad))
continue;
if (polyspace::isPolyspaceComment(tok->str())) {
inlineSuppressions = polyspaceParser.parse(tok->str(), tok->location.line, getRelativeFilename(tokens, tok, settings));
} else {
if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad))
continue;

if (!sameline(tok->previous, tok)) {
// find code after comment..
if (tok->next) {
tok = tok->next;
if (!sameline(tok->previous, tok)) {
// find code after comment..
if (tok->next) {
tok = tok->next;

while (tok->comment) {
parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad);
if (tok->next) {
tok = tok->next;
} else {
break;
while (tok->comment) {
parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad);
if (tok->next) {
tok = tok->next;
} else {
break;
}
}
}
}
Expand Down Expand Up @@ -249,8 +255,9 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
for (SuppressionList::Suppression &suppr : inlineSuppressions) {
suppr.fileName = relativeFilename;

if (SuppressionList::Type::blockBegin == suppr.type)
{
if (SuppressionList::Type::block == suppr.type) {
suppressions.addSuppression(std::move(suppr));
} else if (SuppressionList::Type::blockBegin == suppr.type) {
inlineSuppressionsBlockBegin.push_back(std::move(suppr));
} else if (SuppressionList::Type::blockEnd == suppr.type) {
bool throwError = true;
Expand Down
261 changes: 256 additions & 5 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 @@ -244,6 +245,15 @@ SuppressionList::Suppression SuppressionList::parseLine(const std::string &line)
suppression.fileName.erase(pos);
}
}

// when parsing string generated internally by toString() there can be newline
std::string extra;
while (std::getline(lineStream, extra)) {
if (startsWith(extra, "symbol="))
suppression.symbolName = extra.substr(7);
else if (extra == "polyspace=1")
suppression.isPolyspace = true;
}
}
}

Expand Down Expand Up @@ -632,7 +642,7 @@ void SuppressionList::markUnmatchedInlineSuppressionsAsChecked(const Tokenizer &
std::string SuppressionList::Suppression::toString() const
{
std::string s;
s+= errorId;
s += errorId;
if (!fileName.empty()) {
s += ':';
s += fileName;
Expand All @@ -641,9 +651,250 @@ std::string SuppressionList::Suppression::toString() const
s += std::to_string(lineNumber);
}
}
if (!symbolName.empty()) {
s += ':';
s += symbolName;
}
if (!symbolName.empty())
s += "\nsymbol=" + symbolName;
if (isPolyspace)
s += "\npolyspace=1";
return s;
}

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

if (haveMisraAddon) {
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;

const char prevChar = (pos > 0) ? args[pos - 1] : ' ';
const char nextChar = (pos + arg.size() < args.size()) ? args[pos + arg.size()] : ' ';

return prevChar == ' ' && (nextChar == ' ' || nextChar == ':');
};

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

polyspace::CommentKind polyspace::Parser::parseKind(const std::string& comment, std::string::size_type& pos)
{
const std::string::size_type pos1 = pos;
pos = comment.find_first_of(" \t", pos);
if (pos >= comment.size())
return CommentKind::Invalid;

const std::string token = comment.substr(pos1, pos-pos1);

if (token == "polyspace")
return CommentKind::Regular;

if (token == "polyspace-begin")
return CommentKind::Begin;

if (token == "polyspace-end")
return CommentKind::End;

return CommentKind::Invalid;
}


std::list<SuppressionList::Suppression> polyspace::Parser::parse(const std::string &comment, int line, const std::string &filename) const
{
// Syntax for a polyspace suppression:
// https://se.mathworks.com/help/bugfinder/ug/annotate-hide-known-acceptable-polyspace-results-web-browser.html

std::list<SuppressionList::Suppression> ret;

if (mFamilyMap.empty())
return ret;

for (std::string::size_type pos = comment.find_first_not_of("/* "); pos < comment.size();) {
// polyspace
const auto polyspaceKind = parseKind(comment, pos);
if (polyspaceKind == CommentKind::Invalid)
break;

// optional range
const int rangeValue = parseRange(comment, pos);

// ids..
const std::set<std::string> ids = parseIds(comment, pos);

// skip justification
if (pos < comment.size() && comment[pos] == '[') {
pos = comment.find(']',pos+1);
if (pos >= comment.size())
break;
pos = comment.find_first_not_of(" \t", pos+1);
if (pos >= comment.size())
break;
}

// extra comment
std::string extraComment;
if (pos < comment.size() && comment[pos] == '\"') {
const std::string::size_type p1 = pos + 1;
pos = comment.find('\"',p1);
if (pos >= comment.size())
break;
extraComment = comment.substr(p1, pos-p1);
}

for (const std::string& errorId: ids) {
SuppressionList::Suppression suppr;
suppr.errorId = errorId;
suppr.isInline = true;
suppr.isPolyspace = true;
suppr.fileName = filename;
suppr.lineNumber = line;
suppr.extraComment = extraComment;

if (rangeValue > 0) {
suppr.type = SuppressionList::Type::block;
suppr.lineBegin = line;
suppr.lineEnd = line + rangeValue;
}
else if (polyspaceKind == polyspace::CommentKind::Regular)
suppr.type = SuppressionList::Type::unique;
else if (polyspaceKind == polyspace::CommentKind::Begin)
suppr.type = SuppressionList::Type::blockBegin;
else
suppr.type = SuppressionList::Type::blockEnd;

ret.emplace_back(suppr);
}

// proceed to next "polyspace" if it exists
if (pos < comment.size())
pos = comment.find("polyspace", pos);
}

return ret;
}


int polyspace::Parser::parseRange(const std::string& comment, std::string::size_type& pos) {
pos = comment.find_first_not_of(" \t", pos);
if (pos >= comment.size())
return 0;
if (comment[pos] != '+')
return 0;
const std::string::size_type startpos = pos + 1;
std::string::size_type endpos = comment.find_first_of(" \t", startpos);
if (endpos > comment.size())
return 0;
const std::string range = comment.substr(startpos, endpos-startpos);
try {
int ret = std::stoi(range);
pos = endpos;
return ret;
} catch (const std::invalid_argument &) {}
return 0;
}

std::vector<std::pair<std::string, std::string>> polyspace::Parser::parseFamilyRules(const std::string& comment, std::string::size_type& pos) {
std::vector<std::pair<std::string, std::string>> fr;
std::string family;
std::string rule;
enum class State: uint8_t { family, colon, rule, rule_or_family } state = State::family;
const std::string::size_type endpos = startsWith(comment, "/*") ? comment.size() - 2 : comment.size();
for (; pos <= endpos; ++pos) {
const char c = comment[pos];
if (std::strchr("[\"", c))
break;
switch (state) {
case State::family:
if (std::isalnum(c) || std::strchr("-_.",c))
family += c;
else if (!family.empty() && std::strchr(" \t:",c))
state = State::colon;
break;
case State::colon:
if (!std::strchr(" \t:", c)) {
rule.clear();
--pos;
state = State::rule;
}
break;
case State::rule:
if (std::strchr(", \t",c)) {
if (!rule.empty()) {
fr.emplace_back(family,rule);
rule.clear();
if (c != ',')
state = State::rule_or_family;
}
}
else
rule += c;
break;
case State::rule_or_family:
rule.clear();
if (std::isalnum(c)) {
--pos;
family.clear();
state = State::family;
} else if (c == ',') {
--pos;
state = State::rule;
}
break;
}
}
if (!family.empty() && !rule.empty())
fr.emplace_back(family,rule);
return fr;
}

std::set<std::string> polyspace::Parser::parseIds(const std::string& comment, std::string::size_type& pos) const {
std::set<std::string> ids;
for (const auto& fr: parseFamilyRules(comment,pos)) {
const auto it = mFamilyMap.find(fr.first);
if (it != mFamilyMap.cend())
ids.emplace(it->second + fr.second);
}
return ids;
}


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