Skip to content

Commit 106f6dd

Browse files
committed
1
1 parent 803fdfe commit 106f6dd

7 files changed

Lines changed: 642 additions & 3 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ $(libcppdir)/standards.o: lib/standards.cpp externals/simplecpp/simplecpp.h lib/
652652
$(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
653653
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/summaries.cpp
654654

655-
$(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
655+
$(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
656656
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/suppressions.cpp
657657

658658
$(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

cli/cppcheckexecutor.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ static bool reportUnmatchedSuppressions(const std::list<SuppressionList::Suppres
329329
if (!s.fileName.empty()) {
330330
callStack.emplace_back(s.fileName, s.lineNumber, 0);
331331
}
332-
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal));
332+
const std::string unmatchedSuppressionId = s.isPolyspace ? "unmatchedPolyspaceSuppression" : "unmatchedSuppression";
333+
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, unmatchedSuppressionId, Certainty::normal));
333334
err = true;
334335
}
335336
return err;

lib/preprocessor.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,12 +200,19 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
200200

201201
bool onlyComments = true;
202202

203+
polyspace::Parser polyspaceParser(settings);
204+
203205
for (const simplecpp::Token *tok = tokens.cfront(); tok; tok = tok->next) {
204206
if (!tok->comment) {
205207
onlyComments = false;
206208
continue;
207209
}
208210

211+
if (polyspace::isPolyspaceComment(tok->str())) {
212+
polyspaceParser.parse(tok->str(), tok->location.line, getRelativeFilename(tokens, tok, settings));
213+
continue;
214+
}
215+
209216
std::list<SuppressionList::Suppression> inlineSuppressions;
210217
if (!parseInlineSuppressionCommentToken(tokens, tok, inlineSuppressions, bad))
211218
continue;
@@ -310,6 +317,8 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
310317
for (const SuppressionList::Suppression & suppr: inlineSuppressionsBlockBegin)
311318
// cppcheck-suppress useStlAlgorithm
312319
bad.emplace_back(suppr.fileName, suppr.lineNumber, 0, "Suppress Begin: No matching end"); // TODO: set column
320+
321+
polyspaceParser.collect(suppressions);
313322
}
314323

315324
void Preprocessor::inlineSuppressions(SuppressionList &suppressions)

lib/suppressions.cpp

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "token.h"
2727
#include "tokenize.h"
2828
#include "tokenlist.h"
29+
#include "settings.h"
2930

3031
#include <algorithm>
3132
#include <cctype> // std::isdigit, std::isalnum, etc
@@ -647,3 +648,333 @@ std::string SuppressionList::Suppression::toString() const
647648
}
648649
return s;
649650
}
651+
652+
polyspace::Parser::Parser(const Settings &settings)
653+
{
654+
const auto haveMisraAddon = std::any_of(settings.addonInfos.cbegin(),
655+
settings.addonInfos.cend(),
656+
[] (const AddonInfo &info) {
657+
return info.name == "misra";
658+
});
659+
660+
if (haveMisraAddon) {
661+
mFamilyMap["MISRA-C3"] = "misra-c2012-";
662+
mFamilyMap["MISRA2012"] = "misra-c2012-";
663+
}
664+
665+
const auto matchArg = [&](const std::string &arg) {
666+
const std::string args = settings.premiumArgs;
667+
const std::string::size_type pos = args.find(arg);
668+
669+
if (pos == std::string::npos)
670+
return false;
671+
672+
if (pos > 0 && args[pos - 1] != ' ')
673+
return false;
674+
675+
return pos == args.size() - arg.size() || args[pos + arg.size()] == ' ';
676+
};
677+
678+
if (matchArg("--misra-c-2012")) {
679+
mFamilyMap["MISRA-C3"] = "premium-misra-c-2012-";
680+
mFamilyMap["MISRA2012"] = "premium-misra-c-2012-";
681+
}
682+
683+
if (matchArg("--misra-c-2023"))
684+
mFamilyMap["MISRA-C-2023"] = "premium-misra-c-2023-";
685+
686+
if (matchArg("--misra-cpp-2008") || matchArg("--misra-c++-2008"))
687+
mFamilyMap["MISRA-CPP"] = "premium-misra-cpp-2008-";
688+
689+
if (matchArg("--misra-cpp-2023") || matchArg("--misra-c++-2023"))
690+
mFamilyMap["MISRA-CPP-2023"] = "premium-misra-cpp-2023-";
691+
692+
if (matchArg("--cert-c") || matchArg("--cert-c-2016"))
693+
mFamilyMap["CERT-C"] = "premium-cert-c-";
694+
695+
if (matchArg("--cert-cpp") || matchArg("--cert-c++") ||
696+
matchArg("--cert-cpp-2016") || matchArg("--cert-c++-2016"))
697+
mFamilyMap["CERT-CPP"] = "premium-cert-cpp-";
698+
699+
if (matchArg("--autosar"))
700+
mFamilyMap["AUTOSAR-CPP14"] = "premium-autosar-";
701+
}
702+
703+
std::string polyspace::Parser::peekToken()
704+
{
705+
if (!mHasPeeked) {
706+
mPeeked = nextToken();
707+
mHasPeeked = true;
708+
}
709+
return mPeeked;
710+
}
711+
712+
std::string polyspace::Parser::nextToken()
713+
{
714+
if (mHasPeeked) {
715+
mHasPeeked = false;
716+
return mPeeked;
717+
}
718+
719+
std::string::size_type pos = 0;
720+
while (mComment[pos] == ' ') {
721+
pos++;
722+
if (pos == mComment.size()) {
723+
mComment = "";
724+
return "";
725+
}
726+
}
727+
728+
if (mComment.compare(0, 2, "*/") == 0) {
729+
mComment = "";
730+
return "";
731+
}
732+
733+
if (mComment[pos] == ':') {
734+
mComment = mComment.substr(pos + 1);
735+
return ":";
736+
}
737+
738+
if (mComment[pos] == ',') {
739+
mComment = mComment.substr(pos + 1);
740+
return ",";
741+
}
742+
743+
const char *stopChars;
744+
std::string::size_type skip;
745+
switch (mComment[pos]) {
746+
case '\"':
747+
stopChars = "\"";
748+
skip = 1;
749+
break;
750+
case '[':
751+
stopChars = "]";
752+
skip = 1;
753+
break;
754+
default:
755+
stopChars = " :,";
756+
skip = 0;
757+
break;
758+
}
759+
760+
const std::string::size_type start = pos;
761+
pos += skip;
762+
763+
if (pos == mComment.size()) {
764+
mComment = "";
765+
return "";
766+
}
767+
768+
while (std::strchr(stopChars, mComment[pos]) == nullptr) {
769+
pos++;
770+
if (pos == mComment.size())
771+
break;
772+
}
773+
774+
if (pos == mComment.size())
775+
skip = 0;
776+
777+
const std::string token = mComment.substr(start, pos - start + skip);
778+
mComment = mComment.substr(pos + skip);
779+
780+
return token;
781+
}
782+
783+
bool polyspace::Parser::parseAnnotation(polyspace::Annotation &annotation)
784+
{
785+
annotation.family = nextToken();
786+
annotation.resultNames.clear();
787+
annotation.extraComment = "";
788+
789+
if (annotation.family.empty())
790+
return false;
791+
792+
if (nextToken() != ":")
793+
return false;
794+
795+
for (;;) {
796+
const std::string resultName = nextToken();
797+
798+
if (resultName.empty())
799+
return false;
800+
801+
annotation.resultNames.push_back(resultName);
802+
803+
if (peekToken().substr(0, 1) == ",") {
804+
(void) nextToken();
805+
continue;
806+
}
807+
808+
break;
809+
}
810+
811+
if (peekToken().substr(0, 1) == "[")
812+
(void) nextToken();
813+
814+
if (peekToken().substr(0, 1) == "\"") {
815+
std::string extraComment = nextToken().substr(1);
816+
817+
if (extraComment.size() > 1)
818+
extraComment.pop_back();
819+
820+
annotation.extraComment = extraComment;
821+
}
822+
823+
return true;
824+
}
825+
826+
polyspace::CommentKind polyspace::Parser::parseKind()
827+
{
828+
const std::string token = nextToken();
829+
830+
if (token == "polyspace")
831+
return CommentKind::Regular;
832+
833+
if (token == "polyspace-begin")
834+
return CommentKind::Begin;
835+
836+
if (token == "polyspace-end")
837+
return CommentKind::End;
838+
839+
return CommentKind::Invalid;
840+
}
841+
842+
int polyspace::Parser::parseRange()
843+
{
844+
if (peekToken()[0] == '+') {
845+
try {
846+
const int range = std::stoi(peekToken().substr(1));
847+
(void) nextToken();
848+
return range;
849+
} catch (...) {
850+
return -1;
851+
}
852+
}
853+
854+
return 0;
855+
}
856+
857+
void polyspace::Parser::handleAnnotation(const polyspace::Annotation &annotation)
858+
{
859+
for (const auto &resultName : annotation.resultNames) {
860+
Suppression suppr = {
861+
annotation.family,
862+
resultName,
863+
annotation.filename,
864+
annotation.extraComment,
865+
0,
866+
0,
867+
};
868+
869+
switch (annotation.kind) {
870+
case CommentKind::Regular:
871+
{
872+
suppr.lineBegin = annotation.line;
873+
suppr.lineEnd = annotation.line + annotation.range;
874+
mDone.push_back(suppr);
875+
break;
876+
}
877+
case CommentKind::Begin:
878+
{
879+
suppr.lineBegin = annotation.line;
880+
mStarted.push_back(suppr);
881+
break;
882+
}
883+
case CommentKind::End:
884+
{
885+
auto it = std::find_if(
886+
mStarted.begin(),
887+
mStarted.end(),
888+
[&] (const Suppression &other) {
889+
return suppr.matches(other);
890+
}
891+
);
892+
893+
if (it == mStarted.end())
894+
break;
895+
896+
suppr.lineBegin = it->lineBegin;
897+
suppr.lineEnd = annotation.line;
898+
mStarted.erase(it);
899+
mDone.push_back(suppr);
900+
break;
901+
}
902+
case CommentKind::Invalid:
903+
{
904+
assert(false); // Invalid comments are not handled
905+
}
906+
}
907+
}
908+
}
909+
910+
void polyspace::Parser::collect(SuppressionList &suppressions) const
911+
{
912+
for (const auto &polyspaceSuppr : mDone) {
913+
const auto it = mFamilyMap.find(polyspaceSuppr.family);
914+
if (it == mFamilyMap.cend())
915+
continue;
916+
917+
SuppressionList::Suppression suppr;
918+
suppr.errorId = it->second + polyspaceSuppr.resultName;
919+
suppr.isInline = true;
920+
suppr.isPolyspace = true;
921+
suppr.fileName = polyspaceSuppr.filename;
922+
suppr.extraComment = polyspaceSuppr.extraComment;
923+
924+
suppr.lineNumber = polyspaceSuppr.lineBegin;
925+
if (polyspaceSuppr.lineBegin == polyspaceSuppr.lineEnd) {
926+
suppr.type = SuppressionList::Type::unique;
927+
} else {
928+
suppr.type = SuppressionList::Type::block;
929+
suppr.lineBegin = polyspaceSuppr.lineBegin;
930+
suppr.lineEnd = polyspaceSuppr.lineEnd;
931+
}
932+
933+
suppressions.addSuppression(std::move(suppr));
934+
}
935+
}
936+
937+
void polyspace::Parser::parse(const std::string &comment, int line, const std::string &filename)
938+
{
939+
if (mFamilyMap.empty())
940+
return;
941+
942+
mComment = comment.substr(2);
943+
mHasPeeked = false;
944+
945+
while (true) {
946+
const CommentKind kind = parseKind();
947+
if (kind == CommentKind::Invalid)
948+
return;
949+
950+
const int range = parseRange();
951+
if (range < 0)
952+
return;
953+
954+
Annotation annotation;
955+
annotation.filename = filename;
956+
annotation.kind = kind;
957+
annotation.line = line;
958+
annotation.range = range;
959+
960+
while (parseAnnotation(annotation)) {
961+
handleAnnotation(annotation);
962+
if (!annotation.extraComment.empty())
963+
break;
964+
}
965+
}
966+
}
967+
968+
bool polyspace::isPolyspaceComment(const std::string &comment)
969+
{
970+
const std::string polyspace = "polyspace";
971+
const std::string::size_type pos = comment.find_first_not_of("/* ");
972+
if (pos == std::string::npos)
973+
return false;
974+
return comment.compare(pos, polyspace.size(), polyspace, 0, polyspace.size()) == 0;
975+
}
976+
977+
bool polyspace::Suppression::matches(const polyspace::Suppression &other) const
978+
{
979+
return family == other.family && resultName == other.resultName;
980+
}

0 commit comments

Comments
 (0)