Skip to content

Commit

Permalink
Added new inline suppression
Browse files Browse the repository at this point in the history
  • Loading branch information
JohanBertrand committed Sep 4, 2023
1 parent 4e633e1 commit 19b3cef
Show file tree
Hide file tree
Showing 5 changed files with 521 additions and 35 deletions.
136 changes: 112 additions & 24 deletions lib/preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ Preprocessor::~Preprocessor()

namespace {
struct BadInlineSuppression {
BadInlineSuppression(const simplecpp::Location &l, std::string msg) : location(l), errmsg(std::move(msg)) {}
simplecpp::Location location;
BadInlineSuppression(const std::string file, const int line, std::string msg) : file(file), line(line), errmsg(std::move(msg)) {}
std::string file;
int line;
std::string errmsg;
};
}
Expand All @@ -96,18 +97,50 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std:
if (comment.substr(pos1, cppchecksuppress.size()) != cppchecksuppress)
return false;

// skip spaces after "cppcheck-suppress"
const std::string::size_type pos2 = comment.find_first_not_of(' ', pos1+cppchecksuppress.size());
// check if it has a prefix
const std::string::size_type posEndComment = comment.find_first_of(" [", pos1+cppchecksuppress.size());

// skip spaces after "cppcheck-suppress" and its possible prefix
const std::string::size_type pos2 = comment.find_first_not_of(' ', posEndComment);
if (pos2 == std::string::npos)
return false;

Suppressions::Type errorType = Suppressions::Type::unique;

// determine prefix if specified
if (posEndComment >= (pos1 + cppchecksuppress.size() + 1)) {
if (comment.at(pos1 + cppchecksuppress.size()) != '-')
return false;

const unsigned int argumentLength =
posEndComment - (pos1 + cppchecksuppress.size() + 1);

const std::string suppressTypeString =
comment.substr(pos1 + cppchecksuppress.size() + 1, argumentLength);

if ("file" == suppressTypeString) {
errorType = Suppressions::Type::file;
} else if ("begin" == suppressTypeString) {
errorType = Suppressions::Type::blockBegin;
} else if ("end" == suppressTypeString) {
errorType = Suppressions::Type::blockEnd;
} else {
return false;
}
}

if (comment[pos2] == '[') {
// multi suppress format
std::string errmsg;
std::vector<Suppressions::Suppression> suppressions = Suppressions::parseMultiSuppressComment(comment, &errmsg);

for (Suppressions::Suppression &s : suppressions) {
s.type = errorType;
s.lineNumber = tok->location.line;
}

if (!errmsg.empty())
bad.emplace_back(tok->location, std::move(errmsg));
bad.emplace_back(tok->location.file(), tok->location.line, std::move(errmsg));

std::copy_if(suppressions.cbegin(), suppressions.cend(), std::back_inserter(inlineSuppressions), [](const Suppressions::Suppression& s) {
return !s.errorId.empty();
Expand All @@ -119,18 +152,23 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std:
if (!s.parseComment(comment, &errmsg))
return false;

s.type = errorType;
s.lineNumber = tok->location.line;

if (!s.errorId.empty())
inlineSuppressions.push_back(std::move(s));

if (!errmsg.empty())
bad.emplace_back(tok->location, std::move(errmsg));
bad.emplace_back(tok->location.file(), tok->location.line, std::move(errmsg));
}

return true;
}

static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Settings &settings, Suppressions &suppressions, std::list<BadInlineSuppression> &bad)
{
std::list<Suppressions::Suppression> inlineSuppressionsBlockBegin;

for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) {
if (!tok->comment)
continue;
Expand All @@ -141,13 +179,18 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett

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

while (tok->comment) {
parseInlineSuppressionCommentToken(tok, inlineSuppressions, bad);
if (tok->next) {
tok = tok->next;
} else {
break;
}
}
}
if (!tok)
break;
}

if (inlineSuppressions.empty())
Expand All @@ -165,21 +208,66 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
}
relativeFilename = Path::simplifyPath(relativeFilename);

// special handling when suppressing { warnings for backwards compatibility
const bool thisAndNextLine = tok->previous &&
tok->previous->previous &&
tok->next &&
!sameline(tok->previous->previous, tok->previous) &&
tok->location.line + 1 == tok->next->location.line &&
tok->location.fileIndex == tok->next->location.fileIndex &&
tok->previous->str() == "{";

// Add the suppressions.
for (Suppressions::Suppression &suppr : inlineSuppressions) {
suppr.fileName = relativeFilename;
suppr.lineNumber = tok->location.line;
suppr.thisAndNextLine = thisAndNextLine;
suppressions.addSuppression(std::move(suppr));

if (Suppressions::Type::blockBegin == suppr.type)
{
inlineSuppressionsBlockBegin.push_back(std::move(suppr));
} else if (Suppressions::Type::blockEnd == suppr.type) {
bool throwError = true;

if (inlineSuppressionsBlockBegin.size() > 0) {
const Suppressions::Suppression lastBeginSuppression = inlineSuppressionsBlockBegin.back();

for (Suppressions::Suppression &supprBegin : inlineSuppressionsBlockBegin)
{
if (lastBeginSuppression.lineNumber != supprBegin.lineNumber)
continue;

if (suppr.symbolName == supprBegin.symbolName && suppr.lineNumber > supprBegin.lineNumber) {
suppr.lineBegin = supprBegin.lineNumber;
suppr.lineEnd = suppr.lineNumber;
suppr.lineNumber = supprBegin.lineNumber;
suppr.type = Suppressions::Type::block;
inlineSuppressionsBlockBegin.remove(supprBegin);
suppressions.addSuppression(std::move(suppr));
throwError = false;
break;
}
}
}

if (throwError) {
bad.emplace_back(suppr.fileName, suppr.lineNumber, "Suppress End: No matching begin");
}
} else if (Suppressions::Type::unique == suppr.type) {
if (!tok) {
bad.emplace_back(suppr.fileName, suppr.lineNumber, "Unique suppress without matching code");
} else {
// special handling when suppressing { warnings for backwards compatibility
const bool thisAndNextLine = tok->previous &&
tok->previous->previous &&
tok->next &&
!sameline(tok->previous->previous, tok->previous) &&
tok->location.line + 1 == tok->next->location.line &&
tok->location.fileIndex == tok->next->location.fileIndex &&
tok->previous->str() == "{";

suppr.thisAndNextLine = thisAndNextLine;
suppr.lineNumber = tok->location.line;
suppressions.addSuppression(std::move(suppr));
}
} else {
suppressions.addSuppression(std::move(suppr));
}
}
}

if (inlineSuppressionsBlockBegin.size() > 0) {
for (Suppressions::Suppression &suppr : inlineSuppressionsBlockBegin) {
bad.emplace_back(suppr.fileName, suppr.lineNumber, "Suppress Begin: No matching end");
}
}
}
Expand All @@ -195,7 +283,7 @@ void Preprocessor::inlineSuppressions(const simplecpp::TokenList &tokens, Suppre
::addInlineSuppressions(*it->second, mSettings, suppressions, err);
}
for (const BadInlineSuppression &bad : err) {
error(bad.location.file(), bad.location.line, bad.errmsg);
error(bad.file, bad.line, bad.errmsg);
}
}

Expand Down
37 changes: 28 additions & 9 deletions lib/suppressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,17 @@ std::vector<Suppressions::Suppression> Suppressions::parseMultiSuppressComment(c
return suppressions;
}

const std::string SymbolNameString = "symbolName=";

while (iss) {
std::string word;
iss >> word;
if (!iss)
break;
if (word.find_first_not_of("+-*/%#;") == std::string::npos)
break;
if (word.compare(0, 11, "symbolName=") == 0) {
s.symbolName = word.substr(11);
if (word.compare(0, SymbolNameString.size(), SymbolNameString) == 0) {
s.symbolName = word.substr(SymbolNameString.size());
} else {
if (errorMessage && errorMessage->empty())
*errorMessage = "Bad multi suppression '" + comment + "'. legal format is cppcheck-suppress[errorId, errorId symbolName=arr, ...]";
Expand Down Expand Up @@ -301,23 +303,29 @@ bool Suppressions::Suppression::parseComment(std::string comment, std::string *e

if (comment.compare(comment.size() - 2, 2, "*/") == 0)
comment.erase(comment.size() - 2, 2);

const std::string cppchecksuppress = "cppcheck-suppress";

std::istringstream iss(comment.substr(2));
std::string word;
iss >> word;
if (word != "cppcheck-suppress")
if (word.substr(0, cppchecksuppress.size()) != cppchecksuppress)
return false;

iss >> errorId;
if (!iss)
return false;

const std::string SymbolNameString = "symbolName=";

while (iss) {
iss >> word;
if (!iss)
break;
if (word.find_first_not_of("+-*/%#;") == std::string::npos)
break;
if (word.compare(0,11,"symbolName=")==0)
symbolName = word.substr(11);
if (word.compare(0,SymbolNameString.size(),SymbolNameString)==0)
symbolName = word.substr(SymbolNameString.size());
else if (errorMessage && errorMessage->empty())
*errorMessage = "Bad suppression attribute '" + word + "'. You can write comments in the comment after a ; or //. Valid suppression attributes; symbolName=sym";
}
Expand All @@ -332,10 +340,12 @@ bool Suppressions::Suppression::isSuppressed(const Suppressions::ErrorMessage &e
return false;
if (!fileName.empty() && !matchglob(fileName, errmsg.getFileName()))
return false;
if (lineNumber != NO_LINE && lineNumber != errmsg.lineNumber) {
if (Suppressions::Type::unique == type && lineNumber != NO_LINE && lineNumber != errmsg.lineNumber) {
if (!thisAndNextLine || lineNumber + 1 != errmsg.lineNumber)
return false;
}
if (Suppressions::Type::block == type && (errmsg.lineNumber < lineBegin || errmsg.lineNumber > lineEnd))
return false;
if (!symbolName.empty()) {
for (std::string::size_type pos = 0; pos < errmsg.symbolNames.size();) {
const std::string::size_type pos2 = errmsg.symbolNames.find('\n',pos);
Expand Down Expand Up @@ -385,15 +395,16 @@ std::string Suppressions::Suppression::getText() const
bool Suppressions::isSuppressed(const Suppressions::ErrorMessage &errmsg, bool global)
{
const bool unmatchedSuppression(errmsg.errorId == "unmatchedSuppression");
bool return_value = false;
for (Suppression &s : mSuppressions) {
if (!global && !s.isLocal())
continue;
if (unmatchedSuppression && s.errorId != errmsg.errorId)
continue;
if (s.isMatch(errmsg))
return true;
return_value = true;
}
return false;
return return_value;
}

bool Suppressions::isSuppressed(const ::ErrorMessage &errmsg)
Expand Down Expand Up @@ -470,7 +481,15 @@ void Suppressions::markUnmatchedInlineSuppressionsAsChecked(const Tokenizer &tok
currLineNr = tok->linenr();
currFileIdx = tok->fileIndex();
for (auto &suppression : mSuppressions) {
if (!suppression.checked && (suppression.lineNumber == currLineNr) && (suppression.fileName == tokenizer.list.file(tok))) {
if (suppression.type == Suppressions::Type::unique) {
if (!suppression.checked && (suppression.lineNumber == currLineNr) && (suppression.fileName == tokenizer.list.file(tok))) {
suppression.checked = true;
}
} else if (suppression.type == Suppressions::Type::block) {
if ((!suppression.checked && (suppression.lineBegin <= currLineNr) && (suppression.lineEnd >= currLineNr) && suppression.fileName == tokenizer.list.file(tok))){
suppression.checked = true;
}
} else if (!suppression.checked && suppression.fileName == tokenizer.list.file(tok)) {
suppression.checked = true;
}
}
Expand Down
27 changes: 27 additions & 0 deletions lib/suppressions.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ enum class Certainty;
class CPPCHECKLIB Suppressions {
public:

enum class Type {
unique, file, block, blockBegin, blockEnd
};

struct CPPCHECKLIB ErrorMessage {
std::size_t hash;
std::string errorId;
Expand Down Expand Up @@ -77,6 +81,26 @@ class CPPCHECKLIB Suppressions {
return false;
}

bool operator==(const Suppression &other) const {
if (errorId != other.errorId)
return false;
if (lineNumber < other.lineNumber)
return false;
if (fileName != other.fileName)
return false;
if (symbolName != other.symbolName)
return false;
if (hash != other.hash)
return false;
if (type != other.type)
return false;
if (lineBegin != other.lineBegin)
return false;
if (lineEnd != other.lineEnd)
return false;
return true;
}

/**
* Parse inline suppression in comment
* @param comment the full comment text
Expand Down Expand Up @@ -107,6 +131,9 @@ class CPPCHECKLIB Suppressions {
std::string errorId;
std::string fileName;
int lineNumber = NO_LINE;
int lineBegin = NO_LINE;
int lineEnd = NO_LINE;
Type type = Type::unique;
std::string symbolName;
std::size_t hash{};
bool thisAndNextLine{}; // Special case for backwards compatibility: { // cppcheck-suppress something
Expand Down
20 changes: 20 additions & 0 deletions man/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,26 @@ Suppressing multiple ids in one comment by using []:

// cppcheck-suppress [aaaa, bbbb]

Suppressing warnings `aaaa` on a block of code:

// cppcheck-suppress-begin aaaa
...
// cppcheck-suppress-end aaaa

Suppressing multiple ids on a block of code:

// cppcheck-suppress-begin [aaaa, bbbb]
...
// cppcheck-suppress-end [aaaa, bbbb]

Suppressing warnings `aaaa` for a whole file:

// cppcheck-suppress-file aaaa

Suppressing multiple ids for a whole file:

// cppcheck-suppress-file [aaaa, bbbb]

### Comment before code or on same line

The comment can be put before the code or at the same line as the code.
Expand Down
Loading

0 comments on commit 19b3cef

Please sign in to comment.