@@ -647,3 +647,253 @@ std::string SuppressionList::Suppression::toString() const
647647 }
648648 return s;
649649}
650+
651+ std::string polyspace::Parser::peekToken ()
652+ {
653+ if (!mHasPeeked ) {
654+ mPeeked = nextToken ();
655+ mHasPeeked = true ;
656+ }
657+ return mPeeked ;
658+ }
659+
660+ std::string polyspace::Parser::nextToken ()
661+ {
662+ if (mHasPeeked ) {
663+ mHasPeeked = false ;
664+ return mPeeked ;
665+ }
666+
667+ if (mComment .compare (0 , 2 , " /*" ) == 0 || mComment .compare (0 , 2 , " //" ) == 0 )
668+ mComment = mComment .substr (2 );
669+
670+ std::string::size_type pos = 0 ;
671+ while (mComment [pos] == ' ' ) {
672+ pos++;
673+ if (pos == mComment .size ()) {
674+ mComment = " " ;
675+ return " " ;
676+ }
677+ }
678+
679+ if (mComment .compare (0 , 2 , " */" ) == 0 ) {
680+ mComment = " " ;
681+ return " " ;
682+ }
683+
684+ if (mComment [pos] == ' :' ) {
685+ mComment = mComment .substr (pos + 1 );
686+ return " :" ;
687+ }
688+
689+ if (mComment [pos] == ' ,' ) {
690+ mComment = mComment .substr (pos + 1 );
691+ return " ," ;
692+ }
693+
694+ const char *stopChars;
695+ std::string::size_type skip;
696+ switch (mComment [pos]) {
697+ case ' \" ' :
698+ stopChars = " \" " ;
699+ skip = 1 ;
700+ break ;
701+ case ' [' :
702+ stopChars = " ]" ;
703+ skip = 1 ;
704+ break ;
705+ default :
706+ stopChars = " :," ;
707+ skip = 0 ;
708+ break ;
709+ }
710+
711+ const std::string::size_type start = pos;
712+ pos += skip;
713+
714+ if (pos == mComment .size ()) {
715+ mComment = " " ;
716+ return " " ;
717+ }
718+
719+ while (std::strchr (stopChars, mComment [pos]) == nullptr ) {
720+ pos++;
721+ if (pos == mComment .size ())
722+ break ;
723+ }
724+
725+ if (pos == mComment .size ())
726+ skip = 0 ;
727+
728+ const std::string token = mComment .substr (start, pos - start + skip);
729+ mComment = mComment .substr (pos + skip);
730+
731+ return token;
732+ }
733+
734+ void polyspace::Parser::finishSuppression ()
735+ {
736+ Suppression suppr = { mFamily , mResultName , mFilename , 0 , 0 };
737+
738+ switch (mKind ) {
739+ case CommentKind::Regular:
740+ {
741+ suppr.lineBegin = mLine ;
742+ suppr.lineEnd = mLine + mRange ;
743+ mDone .push_back (suppr);
744+ return ;
745+ }
746+ case CommentKind::Begin:
747+ {
748+ suppr.lineBegin = mLine ;
749+ mStarted .push_back (suppr);
750+ return ;
751+ }
752+ case CommentKind::End:
753+ {
754+ auto it = std::find_if (
755+ mStarted .begin (),
756+ mStarted .end (),
757+ [&] (const Suppression &other) {
758+ return suppr.matches (other);
759+ }
760+ );
761+
762+ if (it == mStarted .end ())
763+ return ;
764+
765+ suppr.lineBegin = it->lineBegin ;
766+ suppr.lineEnd = mLine ;
767+ mStarted .erase (it);
768+ mDone .push_back (suppr);
769+ return ;
770+ }
771+ }
772+ }
773+
774+ bool polyspace::Parser::parseEntry ()
775+ {
776+ mFamily = nextToken ();
777+ if (mFamily .empty ())
778+ return false ;
779+
780+ if (nextToken () != " :" )
781+ return false ;
782+
783+ // Parse result name, multiple names may be separated by commas
784+ while (!mComment .empty ()) {
785+ mResultName = nextToken ();
786+ if (mResultName .empty ())
787+ return false ;
788+
789+ finishSuppression ();
790+
791+ if (peekToken () == " ," ) {
792+ (void ) nextToken ();
793+ continue ;
794+ }
795+
796+ break ;
797+ }
798+
799+ // Skip status and severity
800+ if (!peekToken ().empty () && mPeeked [0 ] == ' [' )
801+ (void ) nextToken ();
802+
803+ return true ;
804+ }
805+
806+ void polyspace::Parser::collect (SuppressionList &suppressions) const
807+ {
808+ for (const auto &polyspaceSuppr : mDone ) {
809+ SuppressionList::Suppression suppr;
810+ if (polyspaceSuppr.convert (suppr))
811+ suppressions.addSuppression (std::move (suppr));
812+ }
813+ }
814+
815+ void polyspace::Parser::parse (const std::string &comment, int line, const std::string &filename)
816+ {
817+ mComment = comment;
818+ mLine = line;
819+ mFilename = filename;
820+ mHasPeeked = false ;
821+
822+ while (true ) {
823+ const std::string kindStr = nextToken ();
824+ if (kindStr.empty ())
825+ return ;
826+
827+ if (kindStr == " polyspace" ) mKind = CommentKind::Regular;
828+ else if (kindStr == " polyspace-begin" ) mKind = CommentKind::Begin;
829+ else if (kindStr == " polyspace-end" ) mKind = CommentKind::End;
830+ else return ;
831+
832+ mRange = 0 ;
833+ if (peekToken ()[0 ] == ' +' ) {
834+ try { mRange = std::stoi (mPeeked .substr (1 )); } catch (...) { return ; }
835+ (void ) nextToken ();
836+ }
837+
838+ while (parseEntry ()) {
839+ if (peekToken ().empty () || mPeeked [0 ] == ' \" ' )
840+ break ;
841+ }
842+
843+ if (!peekToken ().empty () && mPeeked [0 ] == ' \" ' ) {
844+ (void ) nextToken ();
845+ if (peekToken ().empty ())
846+ return ;
847+ continue ;
848+ }
849+
850+ break ;
851+ }
852+ }
853+
854+ bool polyspace::isPolyspaceComment (const std::string &comment)
855+ {
856+ const std::string polyspace = " polyspace" ;
857+ const std::string::size_type pos = comment.find_first_not_of (" /* " );
858+ if (pos == std::string::npos)
859+ return false ;
860+ return comment.compare (pos, polyspace.size (), polyspace, 0 , polyspace.size ()) == 0 ;
861+ }
862+
863+ bool polyspace::Suppression::matches (const polyspace::Suppression &other) const
864+ {
865+ return family == other.family && resultName == other.resultName ;
866+ }
867+
868+ bool polyspace::Suppression::convert (SuppressionList::Suppression &suppr) const
869+ {
870+ static const std::map<std::string, std::string> map = {
871+ { " MISRA-C3" , " premium-misra-c-2012-" },
872+ { " MISRA2012" , " premium-misra-c-2012-" },
873+ { " MISRA-C-2023" , " premium-misra-c-2023-" },
874+ { " MISRA-CPP" , " premium-misra-cpp-2008-" },
875+ { " MISRA-CPP-2023" , " premium-misra-cpp-2023-" },
876+ { " CERT-C" , " premium-cert-c-" },
877+ { " CERT-CPP" , " premium-cert-cpp-" },
878+ { " AUTOSAR-CPP14" , " premium-autosar-" },
879+ };
880+
881+ const auto it = map.find (family);
882+ if (it == map.cend ())
883+ return false ;
884+
885+ suppr.errorId = it->second + resultName;
886+ suppr.isInline = true ;
887+ suppr.fileName = filename;
888+
889+ suppr.lineNumber = lineBegin;
890+ if (lineBegin == lineEnd) {
891+ suppr.type = SuppressionList::Type::unique;
892+ } else {
893+ suppr.type = SuppressionList::Type::block;
894+ suppr.lineBegin = lineBegin;
895+ suppr.lineEnd = lineEnd;
896+ }
897+
898+ return true ;
899+ }
0 commit comments