Cppcheck
checkersreport.cpp
Go to the documentation of this file.
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 static bool isCppcheckPremium(const Settings& settings) {
31  return (settings.cppcheckCfgProductName.compare(0, 16, "Cppcheck Premium") == 0);
32 }
33 
34 static bool isMisraRuleActive(const std::set<std::string>& activeCheckers, const std::string& rule) {
35  if (activeCheckers.count("Misra C: " + rule))
36  return true;
37  if (rule == "1.1")
38  return true; // syntax error
39  if (rule == "1.3")
40  return true; // undefined behavior
41  if (rule == "2.1")
42  return activeCheckers.count("CheckCondition::alwaysTrueFalse") != 0;
43  if (rule == "2.6")
44  return activeCheckers.count("CheckOther::checkUnusedLabel") != 0;
45  if (rule == "2.8")
46  return activeCheckers.count("CheckUnusedVar::checkFunctionVariableUsage") != 0;
47  if (rule == "5.3")
48  return activeCheckers.count("CheckOther::checkShadowVariables") != 0;
49  if (rule == "8.13")
50  return activeCheckers.count("CheckOther::checkConstPointer") != 0;
51  if (rule == "9.1")
52  return true; // uninitvar
53  if (rule == "12.5")
54  return activeCheckers.count("CheckOther::checkConstPointer") != 0;
55  if (rule == "14.3")
56  return activeCheckers.count("CheckCondition::alwaysTrueFalse") != 0;
57  if (rule == "17.5")
58  return activeCheckers.count("CheckBufferOverrun::argumentSize") != 0;
59  if (rule == "18.1")
60  return activeCheckers.count("CheckBufferOverrun::pointerArithmetic") != 0;
61  if (rule == "18.2")
62  return activeCheckers.count("CheckOther::checkComparePointers") != 0;
63  if (rule == "18.3")
64  return activeCheckers.count("CheckOther::checkComparePointers") != 0;
65  if (rule == "18.6")
66  return true; // danlingLifetime => error
67  if (rule == "19.1")
68  return activeCheckers.count("CheckOther::checkOverlappingWrite") != 0;
69  if (rule == "20.6")
70  return true; // preprocessorErrorDirective
71  if (rule == "21.13")
72  return activeCheckers.count("CheckFunctions::invalidFunctionUsage") != 0;
73  if (rule == "21.17")
74  return activeCheckers.count("CheckBufferOverrun::bufferOverflow") != 0;
75  if (rule == "21.18")
76  return activeCheckers.count("CheckBufferOverrun::bufferOverflow") != 0;
77  if (rule == "22.1")
78  return true; // memleak => error
79  if (rule == "22.2")
80  return activeCheckers.count("CheckAutoVariables::autoVariables") != 0;
81  if (rule == "22.3")
82  return activeCheckers.count("CheckIO::checkFileUsage") != 0;
83  if (rule == "22.4")
84  return activeCheckers.count("CheckIO::checkFileUsage") != 0;
85  if (rule == "22.6")
86  return activeCheckers.count("CheckIO::checkFileUsage") != 0;
87 
88  return false;
89 }
90 
91 CheckersReport::CheckersReport(const Settings& settings, const std::set<std::string>& activeCheckers)
92  : mSettings(settings), mActiveCheckers(activeCheckers)
93 {}
94 
96 {
97  if (mAllCheckersCount == 0) {
98  countCheckers();
99  }
100  return mActiveCheckersCount;
101 }
102 
104 {
105  if (mAllCheckersCount == 0) {
106  countCheckers();
107  }
108  return mAllCheckersCount;
109 }
110 
112 {
114 
115  for (const auto& checkReq: checkers::allCheckers) {
116  if (mActiveCheckers.count(checkReq.first) > 0)
119  }
120  for (const auto& checkReq: checkers::premiumCheckers) {
121  if (mActiveCheckers.count(checkReq.first) > 0)
124  }
125  if (mSettings.premiumArgs.find("misra-c-") != std::string::npos || mSettings.addons.count("misra")) {
127  const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
128  const bool active = isMisraRuleActive(mActiveCheckers, rule);
129  if (active)
132  }
133  }
134 }
135 
136 std::string CheckersReport::getReport(const std::string& criticalErrors) const
137 {
138  std::ostringstream fout;
139 
140  fout << "Critical errors" << std::endl;
141  fout << "---------------" << std::endl;
142  if (!criticalErrors.empty()) {
143  fout << "There was critical errors (" << criticalErrors << ")" << std::endl;
144  fout << "All checking is skipped for a file with such error" << std::endl;
145  } else {
146  fout << "No critical errors, all files were checked." << std::endl;
147  fout << "Important: Analysis is still not guaranteed to be 'complete' it is possible there are false negatives." << std::endl;
148  }
149 
150  fout << std::endl << std::endl;
151  fout << "Open source checkers" << std::endl;
152  fout << "--------------------" << std::endl;
153 
154  int maxCheckerSize = 0;
155  for (const auto& checkReq: checkers::allCheckers) {
156  const std::string& checker = checkReq.first;
157  if (checker.size() > maxCheckerSize)
158  maxCheckerSize = checker.size();
159  }
160  for (const auto& checkReq: checkers::allCheckers) {
161  const std::string& checker = checkReq.first;
162  const bool active = mActiveCheckers.count(checkReq.first) > 0;
163  const std::string& req = checkReq.second;
164  fout << (active ? "Yes " : "No ") << checker;
165  if (!active && !req.empty())
166  fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << "require:" + req;
167  fout << std::endl;
168  }
169 
170  const bool cppcheckPremium = isCppcheckPremium(mSettings);
171 
172  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  const std::string& substring) {
178  fout << std::endl << std::endl;
179  fout << title << std::endl;
180  fout << std::string(title.size(), '-') << std::endl;
181  if (!cppcheckPremium) {
182  fout << "Not available, Cppcheck Premium is not used" << std::endl;
183  return;
184  }
185  int maxCheckerSize = 0;
186  for (const auto& checkReq: premiumCheckers) {
187  const std::string& checker = checkReq.first;
188  if (checker.find(substring) != std::string::npos && checker.size() > maxCheckerSize)
189  maxCheckerSize = checker.size();
190  }
191  for (const auto& checkReq: premiumCheckers) {
192  const std::string& checker = checkReq.first;
193  if (checker.find(substring) == std::string::npos)
194  continue;
195  std::string req = checkReq.second;
196  bool active = cppcheckPremium && activeCheckers.count(checker) > 0;
197  if (substring == "::") {
198  if (req == "warning")
199  active &= settings.severity.isEnabled(Severity::warning);
200  else if (req == "style")
201  active &= settings.severity.isEnabled(Severity::style);
202  else if (req == "portability")
203  active &= settings.severity.isEnabled(Severity::portability);
204  else if (!req.empty())
205  active = false; // FIXME: handle req
206  }
207  fout << (active ? "Yes " : "No ") << checker;
208  if (!cppcheckPremium) {
209  if (!req.empty())
210  req = "premium," + req;
211  else
212  req = "premium";
213  }
214  if (!req.empty())
215  req = "require:" + req;
216  if (!active)
217  fout << std::string(maxCheckerSize + 4 - checker.size(), ' ') << req;
218  fout << std::endl;
219  }
220  };
221 
222  reportSection("Premium checkers", mSettings, mActiveCheckers, checkers::premiumCheckers, "::");
223  reportSection("Autosar", mSettings, mActiveCheckers, checkers::premiumCheckers, "Autosar: ");
224  reportSection("Cert C", mSettings, mActiveCheckers, checkers::premiumCheckers, "Cert C: ");
225  reportSection("Cert C++", mSettings, mActiveCheckers, checkers::premiumCheckers, "Cert C++: ");
226 
227  int misra = 0;
228  if (mSettings.premiumArgs.find("misra-c-2012") != std::string::npos)
229  misra = 2012;
230  else if (mSettings.premiumArgs.find("misra-c-2023") != std::string::npos)
231  misra = 2023;
232  else if (mSettings.addons.count("misra"))
233  misra = 2012;
234 
235  if (misra == 0) {
236  fout << std::endl << std::endl;
237  fout << "Misra C" << std::endl;
238  fout << "-------" << std::endl;
239  fout << "Misra is not enabled" << std::endl;
240  } else {
241  fout << std::endl << std::endl;
242  fout << "Misra C " << misra << std::endl;
243  fout << "------------" << std::endl;
245  const std::string rule = std::to_string(info.a) + "." + std::to_string(info.b);
246  const bool active = isMisraRuleActive(mActiveCheckers, rule);
247  fout << (active ? "Yes " : "No ") << "Misra C " << misra << ": " << rule;
248  std::string extra;
249  if (misra == 2012 && info.amendment >= 1)
250  extra = " amendment:" + std::to_string(info.amendment);
251  std::string reqs;
252  if (info.amendment >= 3)
253  reqs += ",premium";
254  if (!active && !reqs.empty())
255  extra += " require:" + reqs.substr(1);
256  if (!extra.empty())
257  fout << std::string(7 - rule.size(), ' ') << extra;
258  fout << '\n';
259  }
260  }
261 
262  reportSection("Misra C++ 2008", mSettings, mActiveCheckers, checkers::premiumCheckers, "Misra C++ 2008: ");
263  reportSection("Misra C++ 2023", mSettings, mActiveCheckers, checkers::premiumCheckers, "Misra C++ 2023: ");
264 
265  return fout.str();
266 }
static bool isCppcheckPremium(const Settings &settings)
static bool isMisraRuleActive(const std::set< std::string > &activeCheckers, const std::string &rule)
int getActiveCheckersCount()
std::string getReport(const std::string &criticalErrors) const
const Settings & mSettings
CheckersReport(const Settings &settings, const std::set< std::string > &activeCheckers)
const std::set< std::string > & mActiveCheckers
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
std::unordered_set< std::string > addons
addons, either filename of python/json file or json data
Definition: settings.h:109
std::string cppcheckCfgProductName
cppcheck.cfg: Custom product name
Definition: settings.h:165
std::string premiumArgs
Extra arguments for Cppcheck Premium addon.
Definition: settings.h:273
@ warning
Warning.
@ portability
Portability warning.
@ style
Style warning.
const std::vector< MisraInfo > misraC2012Rules
Definition: checkers.cpp:748
const std::map< std::string, std::string > premiumCheckers
Definition: checkers.cpp:207
const std::map< std::string, std::string > allCheckers
Definition: checkers.cpp:25