LCOV - code coverage report
Current view: top level - lib - checkersreport.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 3 187 1.6 %
Date: 2024-04-28 12:00:40 Functions: 1 8 12.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Cppcheck - A tool for static C/C++ code analysis
       3             :  * Copyright (C) 2007-2024 Cppcheck team.
       4             :  *
       5             :  * This program is free software: you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation, either version 3 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : #include "checkersreport.h"
      20             : 
      21             : #include "checkers.h"
      22             : #include "errortypes.h"
      23             : #include "settings.h"
      24             : 
      25             : #include <map>
      26             : #include <sstream>
      27             : #include <unordered_set>
      28             : #include <vector>
      29             : 
      30           0 : static bool isCppcheckPremium(const Settings& settings) {
      31           0 :     return (settings.cppcheckCfgProductName.compare(0, 16, "Cppcheck Premium") == 0);
      32             : }
      33             : 
      34           0 : static bool isMisraRuleActive(const std::set<std::string>& activeCheckers, const std::string& rule) {
      35           0 :     if (activeCheckers.count("Misra C: " + rule))
      36           0 :         return true;
      37           0 :     if (rule == "1.1")
      38           0 :         return true; // syntax error
      39           0 :     if (rule == "1.3")
      40           0 :         return true; // undefined behavior
      41           0 :     if (rule == "2.1")
      42           0 :         return activeCheckers.count("CheckCondition::alwaysTrueFalse") != 0;
      43           0 :     if (rule == "2.6")
      44           0 :         return activeCheckers.count("CheckOther::checkUnusedLabel") != 0;
      45           0 :     if (rule == "2.8")
      46           0 :         return activeCheckers.count("CheckUnusedVar::checkFunctionVariableUsage") != 0;
      47           0 :     if (rule == "5.3")
      48           0 :         return activeCheckers.count("CheckOther::checkShadowVariables") != 0;
      49           0 :     if (rule == "8.13")
      50           0 :         return activeCheckers.count("CheckOther::checkConstPointer") != 0;
      51           0 :     if (rule == "9.1")
      52           0 :         return true; // uninitvar
      53           0 :     if (rule == "12.5")
      54           0 :         return activeCheckers.count("CheckOther::checkConstPointer") != 0;
      55           0 :     if (rule == "14.3")
      56           0 :         return activeCheckers.count("CheckCondition::alwaysTrueFalse") != 0;
      57           0 :     if (rule == "17.5")
      58           0 :         return activeCheckers.count("CheckBufferOverrun::argumentSize") != 0;
      59           0 :     if (rule == "18.1")
      60           0 :         return activeCheckers.count("CheckBufferOverrun::pointerArithmetic") != 0;
      61           0 :     if (rule == "18.2")
      62           0 :         return activeCheckers.count("CheckOther::checkComparePointers") != 0;
      63           0 :     if (rule == "18.3")
      64           0 :         return activeCheckers.count("CheckOther::checkComparePointers") != 0;
      65           0 :     if (rule == "18.6")
      66           0 :         return true; // danlingLifetime => error
      67           0 :     if (rule == "19.1")
      68           0 :         return activeCheckers.count("CheckOther::checkOverlappingWrite") != 0;
      69           0 :     if (rule == "20.6")
      70           0 :         return true; // preprocessorErrorDirective
      71           0 :     if (rule == "21.13")
      72           0 :         return activeCheckers.count("CheckFunctions::invalidFunctionUsage") != 0;
      73           0 :     if (rule == "21.17")
      74           0 :         return activeCheckers.count("CheckBufferOverrun::bufferOverflow") != 0;
      75           0 :     if (rule == "21.18")
      76           0 :         return activeCheckers.count("CheckBufferOverrun::bufferOverflow") != 0;
      77           0 :     if (rule == "22.1")
      78           0 :         return true;  // memleak => error
      79           0 :     if (rule == "22.2")
      80           0 :         return activeCheckers.count("CheckAutoVariables::autoVariables") != 0;
      81           0 :     if (rule == "22.3")
      82           0 :         return activeCheckers.count("CheckIO::checkFileUsage") != 0;
      83           0 :     if (rule == "22.4")
      84           0 :         return activeCheckers.count("CheckIO::checkFileUsage") != 0;
      85           0 :     if (rule == "22.6")
      86           0 :         return activeCheckers.count("CheckIO::checkFileUsage") != 0;
      87             : 
      88           0 :     return false;
      89             : }
      90             : 
      91          25 : CheckersReport::CheckersReport(const Settings& settings, const std::set<std::string>& activeCheckers)
      92          25 :     : mSettings(settings), mActiveCheckers(activeCheckers)
      93          25 : {}
      94             : 
      95           0 : int CheckersReport::getActiveCheckersCount()
      96             : {
      97           0 :     if (mAllCheckersCount == 0) {
      98           0 :         countCheckers();
      99             :     }
     100           0 :     return mActiveCheckersCount;
     101             : }
     102             : 
     103           0 : int CheckersReport::getAllCheckersCount()
     104             : {
     105           0 :     if (mAllCheckersCount == 0) {
     106           0 :         countCheckers();
     107             :     }
     108           0 :     return mAllCheckersCount;
     109             : }
     110             : 
     111           0 : void CheckersReport::countCheckers()
     112             : {
     113           0 :     mActiveCheckersCount = mAllCheckersCount = 0;
     114             : 
     115           0 :     for (const auto& checkReq: checkers::allCheckers) {
     116           0 :         if (mActiveCheckers.count(checkReq.first) > 0)
     117           0 :             ++mActiveCheckersCount;
     118           0 :         ++mAllCheckersCount;
     119             :     }
     120           0 :     for (const auto& checkReq: checkers::premiumCheckers) {
     121           0 :         if (mActiveCheckers.count(checkReq.first) > 0)
     122           0 :             ++mActiveCheckersCount;
     123           0 :         ++mAllCheckersCount;
     124             :     }
     125           0 :     if (mSettings.premiumArgs.find("misra-c-") != std::string::npos || mSettings.addons.count("misra")) {
     126           0 :         for (const checkers::MisraInfo& info: checkers::misraC2012Rules) {
     127           0 :             const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
     128           0 :             const bool active = isMisraRuleActive(mActiveCheckers, rule);
     129           0 :             if (active)
     130           0 :                 ++mActiveCheckersCount;
     131           0 :             ++mAllCheckersCount;
     132             :         }
     133             :     }
     134           0 : }
     135             : 
     136           0 : std::string CheckersReport::getReport(const std::string& criticalErrors) const
     137             : {
     138           0 :     std::ostringstream fout;
     139             : 
     140           0 :     fout << "Critical errors" << std::endl;
     141           0 :     fout << "---------------" << std::endl;
     142           0 :     if (!criticalErrors.empty()) {
     143           0 :         fout << "There was critical errors (" << criticalErrors << ")" << std::endl;
     144           0 :         fout << "All checking is skipped for a file with such error" << std::endl;
     145             :     } else {
     146           0 :         fout << "No critical errors, all files were checked." << std::endl;
     147           0 :         fout << "Important: Analysis is still not guaranteed to be 'complete' it is possible there are false negatives." << std::endl;
     148             :     }
     149             : 
     150           0 :     fout << std::endl << std::endl;
     151           0 :     fout << "Open source checkers" << std::endl;
     152           0 :     fout << "--------------------" << std::endl;
     153             : 
     154           0 :     int maxCheckerSize = 0;
     155           0 :     for (const auto& checkReq: checkers::allCheckers) {
     156           0 :         const std::string& checker = checkReq.first;
     157           0 :         if (checker.size() > maxCheckerSize)
     158           0 :             maxCheckerSize = checker.size();
     159             :     }
     160           0 :     for (const auto& checkReq: checkers::allCheckers) {
     161           0 :         const std::string& checker = checkReq.first;
     162           0 :         const bool active = mActiveCheckers.count(checkReq.first) > 0;
     163           0 :         const std::string& req = checkReq.second;
     164           0 :         fout << (active ? "Yes  " : "No   ") << checker;
     165           0 :         if (!active && !req.empty())
     166           0 :             fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << "require:" + req;
     167           0 :         fout << std::endl;
     168             :     }
     169             : 
     170           0 :     const bool cppcheckPremium = isCppcheckPremium(mSettings);
     171             : 
     172           0 :     auto reportSection = [&fout, cppcheckPremium]
     173             :                              (const std::string& title,
     174             :                              const Settings& settings,
     175             :                              const std::set<std::string>& activeCheckers,
     176             :                              const std::map<std::string, std::string>& premiumCheckers,
     177           0 :                              const std::string& substring) {
     178           0 :         fout << std::endl << std::endl;
     179           0 :         fout << title << std::endl;
     180           0 :         fout << std::string(title.size(), '-') << std::endl;
     181           0 :         if (!cppcheckPremium) {
     182           0 :             fout << "Not available, Cppcheck Premium is not used" << std::endl;
     183           0 :             return;
     184             :         }
     185           0 :         int maxCheckerSize = 0;
     186           0 :         for (const auto& checkReq: premiumCheckers) {
     187           0 :             const std::string& checker = checkReq.first;
     188           0 :             if (checker.find(substring) != std::string::npos && checker.size() > maxCheckerSize)
     189           0 :                 maxCheckerSize = checker.size();
     190             :         }
     191           0 :         for (const auto& checkReq: premiumCheckers) {
     192           0 :             const std::string& checker = checkReq.first;
     193           0 :             if (checker.find(substring) == std::string::npos)
     194           0 :                 continue;
     195           0 :             std::string req = checkReq.second;
     196           0 :             bool active = cppcheckPremium && activeCheckers.count(checker) > 0;
     197           0 :             if (substring == "::") {
     198           0 :                 if (req == "warning")
     199           0 :                     active &= settings.severity.isEnabled(Severity::warning);
     200           0 :                 else if (req == "style")
     201           0 :                     active &= settings.severity.isEnabled(Severity::style);
     202           0 :                 else if (req == "portability")
     203           0 :                     active &= settings.severity.isEnabled(Severity::portability);
     204           0 :                 else if (!req.empty())
     205           0 :                     active = false; // FIXME: handle req
     206             :             }
     207           0 :             fout << (active ? "Yes  " : "No   ") << checker;
     208           0 :             if (!cppcheckPremium) {
     209           0 :                 if (!req.empty())
     210           0 :                     req = "premium," + req;
     211             :                 else
     212           0 :                     req = "premium";
     213             :             }
     214           0 :             if (!req.empty())
     215           0 :                 req = "require:" + req;
     216           0 :             if (!active)
     217           0 :                 fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << req;
     218           0 :             fout << std::endl;
     219             :         }
     220           0 :     };
     221             : 
     222           0 :     reportSection("Premium checkers", mSettings, mActiveCheckers, checkers::premiumCheckers, "::");
     223           0 :     reportSection("Autosar", mSettings, mActiveCheckers, checkers::premiumCheckers, "Autosar: ");
     224           0 :     reportSection("Cert C", mSettings, mActiveCheckers, checkers::premiumCheckers, "Cert C: ");
     225           0 :     reportSection("Cert C++", mSettings, mActiveCheckers, checkers::premiumCheckers, "Cert C++: ");
     226             : 
     227           0 :     int misra = 0;
     228           0 :     if (mSettings.premiumArgs.find("misra-c-2012") != std::string::npos)
     229           0 :         misra = 2012;
     230           0 :     else if (mSettings.premiumArgs.find("misra-c-2023") != std::string::npos)
     231           0 :         misra = 2023;
     232           0 :     else if (mSettings.addons.count("misra"))
     233           0 :         misra = 2012;
     234             : 
     235           0 :     if (misra == 0) {
     236           0 :         fout << std::endl << std::endl;
     237           0 :         fout << "Misra C" << std::endl;
     238           0 :         fout << "-------" << std::endl;
     239           0 :         fout << "Misra is not enabled" << std::endl;
     240             :     } else {
     241           0 :         fout << std::endl << std::endl;
     242           0 :         fout << "Misra C " << misra << std::endl;
     243           0 :         fout << "------------" << std::endl;
     244           0 :         for (const checkers::MisraInfo& info: checkers::misraC2012Rules) {
     245           0 :             const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
     246           0 :             const bool active = isMisraRuleActive(mActiveCheckers, rule);
     247           0 :             fout << (active ? "Yes  " : "No   ") << "Misra C " << misra << ": " << rule;
     248           0 :             std::string extra;
     249           0 :             if (misra == 2012 && info.amendment >= 1)
     250           0 :                 extra = " amendment:" + std::to_string(info.amendment);
     251           0 :             std::string reqs;
     252           0 :             if (info.amendment >= 3)
     253           0 :                 reqs += ",premium";
     254           0 :             if (!active && !reqs.empty())
     255           0 :                 extra += " require:" + reqs.substr(1);
     256           0 :             if (!extra.empty())
     257           0 :                 fout << std::string(7 - rule.size(), ' ') << extra;
     258           0 :             fout << '\n';
     259             :         }
     260             :     }
     261             : 
     262           0 :     reportSection("Misra C++ 2008", mSettings, mActiveCheckers, checkers::premiumCheckers, "Misra C++ 2008: ");
     263           0 :     reportSection("Misra C++ 2023", mSettings, mActiveCheckers, checkers::premiumCheckers, "Misra C++ 2023: ");
     264             : 
     265           0 :     return fout.str();
     266             : }

Generated by: LCOV version 1.14