cppcheck/lib/settings.cpp
Oliver Stöneberg 45de338f1b
cleaned up includes based on include-what-you-use / iwyu.yml: updated to yet another distro to get the latest version and updated the Chaotic-AUR key (#5267)
This is a mess. The version is AUR is still outdated and also doesn't
install anymore. Fedora 38 carries the latest version of it so use that
now. Keep the old steps in case we need to switch again in the future.
2023-08-02 10:36:17 +02:00

239 lines
7.6 KiB
C++

/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2023 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "settings.h"
#include "path.h"
#include "summaries.h"
#include "timer.h"
#include "vfvalue.h"
#include <fstream>
#define PICOJSON_USE_INT64
#include <picojson.h>
std::atomic<bool> Settings::mTerminated;
const char Settings::SafeChecks::XmlRootName[] = "safe-checks";
const char Settings::SafeChecks::XmlClasses[] = "class-public";
const char Settings::SafeChecks::XmlExternalFunctions[] = "external-functions";
const char Settings::SafeChecks::XmlInternalFunctions[] = "internal-functions";
const char Settings::SafeChecks::XmlExternalVariables[] = "external-variables";
Settings::Settings()
: checkAllConfigurations(true),
checkConfiguration(false),
checkHeaders(true),
checkLibrary(false),
checksMaxTime(0),
checkUnusedTemplates(true),
clang(false),
clangExecutable("clang"),
clangTidy(false),
clearIncludeCache(false),
daca(false),
debugnormal(false),
debugSimplified(false),
debugtemplate(false),
debugwarnings(false),
dump(false),
enforcedLang(Language::None),
exceptionHandling(false),
exitCode(0),
force(false),
inlineSuppressions(false),
jobs(1),
loadAverage(0),
maxConfigs(12),
maxCtuDepth(2),
maxTemplateRecursion(100),
performanceValueFlowMaxTime(-1),
preprocessOnly(false),
quiet(false),
relativePaths(false),
reportProgress(false),
showtime(SHOWTIME_MODES::SHOWTIME_NONE),
templateMaxTime(0),
typedefMaxTime(0),
valueFlowMaxIterations(4),
verbose(false),
xml(false),
xml_version(2)
{
severity.setEnabled(Severity::error, true);
certainty.setEnabled(Certainty::normal, true);
setCheckLevelNormal();
}
void Settings::loadCppcheckCfg()
{
std::string fileName = Path::getPathFromFilename(exename) + "cppcheck.cfg";
#ifdef FILESDIR
if (Path::fileExists(FILESDIR "/cppcheck.cfg"))
fileName = FILESDIR "/cppcheck.cfg";
#endif
std::ifstream fin(fileName);
if (!fin.is_open())
return;
picojson::value json;
fin >> json;
if (!picojson::get_last_error().empty())
return;
picojson::object obj = json.get<picojson::object>();
if (obj.count("productName") && obj["productName"].is<std::string>())
cppcheckCfgProductName = obj["productName"].get<std::string>();
if (obj.count("about") && obj["about"].is<std::string>())
cppcheckCfgAbout = obj["about"].get<std::string>();
if (obj.count("addons") && obj["addons"].is<picojson::array>()) {
for (const picojson::value &v : obj["addons"].get<picojson::array>()) {
const std::string &s = v.get<std::string>();
if (!Path::isAbsolute(s))
addons.emplace(Path::getPathFromFilename(fileName) + s);
else
addons.emplace(s);
}
}
if (obj.count("suppressions") && obj["suppressions"].is<picojson::array>()) {
for (const picojson::value &v : obj["suppressions"].get<picojson::array>())
nomsg.addSuppressionLine(v.get<std::string>());
}
}
std::string Settings::parseEnabled(const std::string &str, std::tuple<SimpleEnableGroup<Severity::SeverityType>, SimpleEnableGroup<Checks>> &groups)
{
// Enable parameters may be comma separated...
if (str.find(',') != std::string::npos) {
std::string::size_type prevPos = 0;
std::string::size_type pos = 0;
while ((pos = str.find(',', pos)) != std::string::npos) {
if (pos == prevPos)
return std::string("--enable parameter is empty");
std::string errmsg(parseEnabled(str.substr(prevPos, pos - prevPos), groups));
if (!errmsg.empty())
return errmsg;
++pos;
prevPos = pos;
}
if (prevPos >= str.length())
return std::string("--enable parameter is empty");
return parseEnabled(str.substr(prevPos), groups);
}
auto& severity = std::get<0>(groups);
auto& checks = std::get<1>(groups);
if (str == "all") {
// "error" is always enabled and cannot be controlled - so exclude it from "all"
SimpleEnableGroup<Severity::SeverityType> newSeverity;
newSeverity.fill();
newSeverity.disable(Severity::SeverityType::error);
severity.enable(newSeverity);
checks.enable(Checks::missingInclude);
checks.enable(Checks::unusedFunction);
} else if (str == "warning") {
severity.enable(Severity::warning);
} else if (str == "style") {
severity.enable(Severity::style);
} else if (str == "performance") {
severity.enable(Severity::performance);
} else if (str == "portability") {
severity.enable(Severity::portability);
} else if (str == "information") {
severity.enable(Severity::information);
} else if (str == "unusedFunction") {
checks.enable(Checks::unusedFunction);
} else if (str == "missingInclude") {
checks.enable(Checks::missingInclude);
}
#ifdef CHECK_INTERNAL
else if (str == "internal") {
checks.enable(Checks::internalCheck);
}
#endif
else {
// the actual option is prepending in the applyEnabled() call
if (str.empty())
return " parameter is empty";
return " parameter with the unknown name '" + str + "'";
}
return "";
}
std::string Settings::addEnabled(const std::string &str)
{
return applyEnabled(str, true);
}
std::string Settings::removeEnabled(const std::string &str)
{
return applyEnabled(str, false);
}
std::string Settings::applyEnabled(const std::string &str, bool enable)
{
std::tuple<SimpleEnableGroup<Severity::SeverityType>, SimpleEnableGroup<Checks>> groups;
std::string errmsg = parseEnabled(str, groups);
if (!errmsg.empty())
return (enable ? "--enable" : "--disable") + errmsg;
const auto s = std::get<0>(groups);
const auto c = std::get<1>(groups);
if (enable) {
severity.enable(s);
checks.enable(c);
}
else {
severity.disable(s);
checks.disable(c);
}
// FIXME: hack to make sure "error" is always enabled
severity.enable(Severity::SeverityType::error);
return errmsg;
}
bool Settings::isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck) const
{
if (!severity.isEnabled(Severity::warning) && (value->condition || value->defaultArg))
return false;
if (!certainty.isEnabled(Certainty::inconclusive) && (inconclusiveCheck || value->isInconclusive()))
return false;
return true;
}
void Settings::loadSummaries()
{
Summaries::loadReturn(buildDir, summaryReturn);
}
void Settings::setCheckLevelExhaustive()
{
// Checking can take a little while. ~ 10 times slower than normal analysis is OK.
performanceValueFlowMaxIfCount = -1;
performanceValueFlowMaxSubFunctionArgs = 256;
}
void Settings::setCheckLevelNormal()
{
// Checking should finish in reasonable time.
performanceValueFlowMaxSubFunctionArgs = 8;
performanceValueFlowMaxIfCount = 100;
}