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