greatly improved `Settings::loadCppcheckCfg()` error handling (#5712)
This also fixes the issue that `cppcheck.cfg` is no longer being loaded from executable path. That was introduced by #5704.
This commit is contained in:
parent
4182f943aa
commit
3272a2bbe7
|
@ -40,4 +40,4 @@ jobs:
|
||||||
- name: Check
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
cppcheckpremium-${{ env.PREMIUM_VERSION }}/premiumaddon --check-loc-license cppcheck.lic > cppcheck-premium-loc
|
cppcheckpremium-${{ env.PREMIUM_VERSION }}/premiumaddon --check-loc-license cppcheck.lic > cppcheck-premium-loc
|
||||||
cppcheckpremium-${{ env.PREMIUM_VERSION }}/cppcheck -j$(nproc) -D__GNUC__ -D__CPPCHECK__ --suppressions-list=cppcheckpremium-suppressions --platform=unix64 --enable=style --premium=misra-c++-2008 --premium=cert-c++-2016 --error-exitcode=1 lib
|
cppcheckpremium-${{ env.PREMIUM_VERSION }}/cppcheck -j$(nproc) -D__GNUC__ -D__CPPCHECK__ --suppressions-list=cppcheckpremium-suppressions --platform=unix64 --enable=style --premium=misra-c++-2008 --premium=cert-c++-2016 --inline-suppr --error-exitcode=1 lib
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -728,7 +728,7 @@ test/testclangimport.o: test/testclangimport.cpp lib/addoninfo.h lib/check.h lib
|
||||||
test/testclass.o: test/testclass.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkclass.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
|
test/testclass.o: test/testclass.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkclass.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testclass.cpp
|
||||||
|
|
||||||
test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
|
test/testcmdlineparser.o: test/testcmdlineparser.cpp cli/cmdlinelogger.h cli/cmdlineparser.h cli/cppcheckexecutor.h lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcmdlineparser.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcmdlineparser.cpp
|
||||||
|
|
||||||
test/testcolor.o: test/testcolor.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
|
test/testcolor.o: test/testcolor.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
|
||||||
|
@ -809,7 +809,7 @@ test/testpreprocessor.o: test/testpreprocessor.cpp externals/simplecpp/simplecpp
|
||||||
test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
|
test/testprocessexecutor.o: test/testprocessexecutor.cpp cli/executor.h cli/processexecutor.h lib/addoninfo.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h test/redirect.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprocessexecutor.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testprocessexecutor.cpp
|
||||||
|
|
||||||
test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/utils.h test/fixture.h
|
test/testsettings.o: test/testsettings.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsettings.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsettings.cpp
|
||||||
|
|
||||||
test/testsimplifytemplate.o: test/testsimplifytemplate.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
|
test/testsimplifytemplate.o: test/testsimplifytemplate.cpp lib/addoninfo.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
|
||||||
|
|
|
@ -282,6 +282,8 @@ bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
|
||||||
// TODO: error out on all missing given files/paths
|
// TODO: error out on all missing given files/paths
|
||||||
CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const argv[])
|
CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const argv[])
|
||||||
{
|
{
|
||||||
|
mSettings.exename = Path::getCurrentExecutablePath(argv[0]);
|
||||||
|
|
||||||
if (argc <= 1) {
|
if (argc <= 1) {
|
||||||
printHelp();
|
printHelp();
|
||||||
return Result::Exit;
|
return Result::Exit;
|
||||||
|
@ -307,7 +309,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
|
||||||
|
|
||||||
// print all possible error messages..
|
// print all possible error messages..
|
||||||
if (std::strcmp(argv[i], "--errorlist") == 0) {
|
if (std::strcmp(argv[i], "--errorlist") == 0) {
|
||||||
mSettings.loadCppcheckCfg();
|
if (!loadCppcheckCfg())
|
||||||
|
return Result::Fail;
|
||||||
{
|
{
|
||||||
XMLErrorMessagesLogger xmlLogger;
|
XMLErrorMessagesLogger xmlLogger;
|
||||||
std::cout << ErrorMessage::getXMLHeader(mSettings.cppcheckCfgProductName);
|
std::cout << ErrorMessage::getXMLHeader(mSettings.cppcheckCfgProductName);
|
||||||
|
@ -324,7 +327,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::strcmp(argv[i], "--version") == 0) {
|
if (std::strcmp(argv[i], "--version") == 0) {
|
||||||
mSettings.loadCppcheckCfg();
|
if (!loadCppcheckCfg())
|
||||||
|
return Result::Fail;
|
||||||
if (!mSettings.cppcheckCfgProductName.empty()) {
|
if (!mSettings.cppcheckCfgProductName.empty()) {
|
||||||
mLogger.printRaw(mSettings.cppcheckCfgProductName);
|
mLogger.printRaw(mSettings.cppcheckCfgProductName);
|
||||||
} else {
|
} else {
|
||||||
|
@ -343,8 +347,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
|
||||||
|
|
||||||
ImportProject project;
|
ImportProject project;
|
||||||
|
|
||||||
mSettings.exename = Path::getCurrentExecutablePath(argv[0]);
|
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (argv[i][0] == '-') {
|
if (argv[i][0] == '-') {
|
||||||
// User define
|
// User define
|
||||||
|
@ -1203,7 +1205,8 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mSettings.loadCppcheckCfg();
|
if (!loadCppcheckCfg())
|
||||||
|
return Result::Fail;
|
||||||
|
|
||||||
// Default template format..
|
// Default template format..
|
||||||
if (mSettings.templateFormat.empty()) {
|
if (mSettings.templateFormat.empty()) {
|
||||||
|
@ -1609,10 +1612,10 @@ void CmdLineParser::printHelp() const
|
||||||
mLogger.printRaw(oss.str());
|
mLogger.printRaw(oss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CmdLineParser::isCppcheckPremium() const {
|
bool CmdLineParser::isCppcheckPremium() {
|
||||||
if (mSettings.cppcheckCfgProductName.empty())
|
Settings settings;
|
||||||
mSettings.loadCppcheckCfg();
|
settings.loadCppcheckCfg(); // TODO: how to handle errors?
|
||||||
return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
|
return startsWith(settings.cppcheckCfgProductName, "Cppcheck Premium");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename)
|
bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename)
|
||||||
|
@ -1701,3 +1704,14 @@ bool CmdLineParser::loadAddons(Settings& settings)
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CmdLineParser::loadCppcheckCfg()
|
||||||
|
{
|
||||||
|
const std::string cfgErr = mSettings.loadCppcheckCfg();
|
||||||
|
if (!cfgErr.empty()) {
|
||||||
|
mLogger.printError("could not load cppcheck.cfg - " + cfgErr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ protected:
|
||||||
void printHelp() const;
|
void printHelp() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isCppcheckPremium() const;
|
static bool isCppcheckPremium();
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool parseNumberArg(const char* const arg, std::size_t offset, T& num, bool mustBePositive = false)
|
bool parseNumberArg(const char* const arg, std::size_t offset, T& num, bool mustBePositive = false)
|
||||||
|
@ -150,6 +150,8 @@ private:
|
||||||
*/
|
*/
|
||||||
bool loadAddons(Settings& settings);
|
bool loadAddons(Settings& settings);
|
||||||
|
|
||||||
|
bool loadCppcheckCfg();
|
||||||
|
|
||||||
CmdLineLogger &mLogger;
|
CmdLineLogger &mLogger;
|
||||||
|
|
||||||
std::vector<std::string> mPathNames;
|
std::vector<std::string> mPathNames;
|
||||||
|
|
|
@ -119,7 +119,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
|
||||||
{
|
{
|
||||||
Settings tempSettings;
|
Settings tempSettings;
|
||||||
tempSettings.exename = QCoreApplication::applicationFilePath().toStdString();
|
tempSettings.exename = QCoreApplication::applicationFilePath().toStdString();
|
||||||
tempSettings.loadCppcheckCfg();
|
tempSettings.loadCppcheckCfg(); // TODO: how to handle error?
|
||||||
mCppcheckCfgProductName = QString::fromStdString(tempSettings.cppcheckCfgProductName);
|
mCppcheckCfgProductName = QString::fromStdString(tempSettings.cppcheckCfgProductName);
|
||||||
mCppcheckCfgAbout = QString::fromStdString(tempSettings.cppcheckCfgAbout);
|
mCppcheckCfgAbout = QString::fromStdString(tempSettings.cppcheckCfgAbout);
|
||||||
}
|
}
|
||||||
|
@ -903,8 +903,7 @@ bool MainWindow::tryLoadLibrary(Library *library, const QString& filename)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings MainWindow::getCppcheckSettings()
|
Settings MainWindow::getCppcheckSettings() {
|
||||||
{
|
|
||||||
saveSettings(); // Save settings
|
saveSettings(); // Save settings
|
||||||
|
|
||||||
Settings result;
|
Settings result;
|
||||||
|
@ -915,7 +914,11 @@ Settings MainWindow::getCppcheckSettings()
|
||||||
if (!std)
|
if (!std)
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured.").arg("std.cfg"));
|
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1. Your Cppcheck installation is broken. You can use --data-dir=<directory> at the command line to specify where this file is located. Please note that --data-dir is supposed to be used by installation scripts and therefore the GUI does not start when it is used, all that happens is that the setting is configured.").arg("std.cfg"));
|
||||||
|
|
||||||
result.loadCppcheckCfg();
|
{
|
||||||
|
const QString cfgErr = QString::fromStdString(result.loadCppcheckCfg());
|
||||||
|
if (!cfgErr.isEmpty())
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1 - %2").arg("cppcheck.cfg").arg(cfgErr));
|
||||||
|
}
|
||||||
|
|
||||||
// If project file loaded, read settings from it
|
// If project file loaded, read settings from it
|
||||||
if (mProjectFile) {
|
if (mProjectFile) {
|
||||||
|
|
|
@ -40,40 +40,87 @@ Settings::Settings()
|
||||||
setCheckLevelNormal();
|
setCheckLevelNormal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: report error when the config is invalid
|
std::string Settings::loadCppcheckCfg()
|
||||||
void Settings::loadCppcheckCfg()
|
|
||||||
{
|
{
|
||||||
std::string fileName = Path::getPathFromFilename(exename) + "cppcheck.cfg";
|
static const std::string cfgFilename = "cppcheck.cfg";
|
||||||
|
std::string fileName;
|
||||||
#ifdef FILESDIR
|
#ifdef FILESDIR
|
||||||
if (Path::isFile(FILESDIR "/cppcheck.cfg"))
|
if (Path::isFile(Path::join(FILESDIR, cfgFilename)))
|
||||||
fileName = FILESDIR "/cppcheck.cfg";
|
fileName = Path::join(FILESDIR, cfgFilename);
|
||||||
#endif
|
#endif
|
||||||
|
// cppcheck-suppress knownConditionTrueFalse
|
||||||
|
if (fileName.empty()) {
|
||||||
|
fileName = Path::getPathFromFilename(exename) + cfgFilename;
|
||||||
|
if (!Path::isFile(fileName))
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
std::ifstream fin(fileName);
|
std::ifstream fin(fileName);
|
||||||
if (!fin.is_open())
|
if (!fin.is_open())
|
||||||
return;
|
return "could not open file";
|
||||||
picojson::value json;
|
picojson::value json;
|
||||||
fin >> json;
|
fin >> json;
|
||||||
if (!picojson::get_last_error().empty())
|
{
|
||||||
return;
|
const std::string& lastErr = picojson::get_last_error();
|
||||||
picojson::object obj = json.get<picojson::object>();
|
if (!lastErr.empty())
|
||||||
if (obj.count("productName") && obj["productName"].is<std::string>())
|
return "not a valid JSON - " + lastErr;
|
||||||
cppcheckCfgProductName = obj["productName"].get<std::string>();
|
}
|
||||||
if (obj.count("about") && obj["about"].is<std::string>())
|
const picojson::object& obj = json.get<picojson::object>();
|
||||||
cppcheckCfgAbout = obj["about"].get<std::string>();
|
{
|
||||||
if (obj.count("addons") && obj["addons"].is<picojson::array>()) {
|
const picojson::object::const_iterator it = obj.find("productName");
|
||||||
for (const picojson::value &v : obj["addons"].get<picojson::array>()) {
|
if (it != obj.cend()) {
|
||||||
|
const auto& v = it->second;
|
||||||
|
if (!v.is<std::string>())
|
||||||
|
return "'productName' is not a string";
|
||||||
|
cppcheckCfgProductName = v.get<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const picojson::object::const_iterator it = obj.find("about");
|
||||||
|
if (it != obj.cend()) {
|
||||||
|
const auto& v = it->second;
|
||||||
|
if (!v.is<std::string>())
|
||||||
|
return "'about' is not a string";
|
||||||
|
cppcheckCfgAbout = v.get<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const picojson::object::const_iterator it = obj.find("addons");
|
||||||
|
if (it != obj.cend()) {
|
||||||
|
const auto& entry = it->second;
|
||||||
|
if (!entry.is<picojson::array>())
|
||||||
|
return "'addons' is not an array";
|
||||||
|
for (const picojson::value &v : entry.get<picojson::array>())
|
||||||
|
{
|
||||||
|
if (!v.is<std::string>())
|
||||||
|
return "'addons' array entry is not a string";
|
||||||
const std::string &s = v.get<std::string>();
|
const std::string &s = v.get<std::string>();
|
||||||
if (!Path::isAbsolute(s))
|
if (!Path::isAbsolute(s))
|
||||||
addons.emplace(Path::getPathFromFilename(fileName) + s);
|
addons.emplace(Path::join(Path::getPathFromFilename(fileName), s));
|
||||||
else
|
else
|
||||||
addons.emplace(s);
|
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>());
|
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const picojson::object::const_iterator it = obj.find("suppressions");
|
||||||
|
if (it != obj.cend()) {
|
||||||
|
const auto& entry = it->second;
|
||||||
|
if (!entry.is<picojson::array>())
|
||||||
|
return "'suppressions' is not an array";
|
||||||
|
for (const picojson::value &v : entry.get<picojson::array>())
|
||||||
|
{
|
||||||
|
if (!v.is<std::string>())
|
||||||
|
return "'suppressions' array entry is not a string";
|
||||||
|
const std::string &s = v.get<std::string>();
|
||||||
|
const std::string err = nomsg.addSuppressionLine(s);
|
||||||
|
if (!err.empty())
|
||||||
|
return "could not parse suppression '" + s + "' - " + err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Settings::parseEnabled(const std::string &str, std::tuple<SimpleEnableGroup<Severity>, SimpleEnableGroup<Checks>> &groups)
|
std::string Settings::parseEnabled(const std::string &str, std::tuple<SimpleEnableGroup<Severity>, SimpleEnableGroup<Checks>> &groups)
|
||||||
|
|
|
@ -99,7 +99,7 @@ private:
|
||||||
public:
|
public:
|
||||||
Settings();
|
Settings();
|
||||||
|
|
||||||
void loadCppcheckCfg();
|
std::string loadCppcheckCfg();
|
||||||
|
|
||||||
/** @brief addons, either filename of python/json file or json data */
|
/** @brief addons, either filename of python/json file or json data */
|
||||||
std::unordered_set<std::string> addons;
|
std::unordered_set<std::string> addons;
|
||||||
|
|
|
@ -32,3 +32,4 @@ Other:
|
||||||
- You can suppress all warnings where macro is used using "-macro"
|
- You can suppress all warnings where macro is used using "-macro"
|
||||||
- fixed CMake build with UBSAN and GCC
|
- fixed CMake build with UBSAN and GCC
|
||||||
- Added command-line options "--fsigned-char" and "--funsigned-char" to control the signess of the "char" type. This overrides previously specified "--platform" options and is overrides by following ones.
|
- Added command-line options "--fsigned-char" and "--funsigned-char" to control the signess of the "char" type. This overrides previously specified "--platform" options and is overrides by following ones.
|
||||||
|
- An error is now reported when the "cppcheck.cfg" is invalid. The CLI version will also exit with a failure in that case.
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "cppcheckexecutor.h"
|
#include "cppcheckexecutor.h"
|
||||||
#include "errortypes.h"
|
#include "errortypes.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "path.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "redirect.h"
|
#include "redirect.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
@ -125,6 +126,7 @@ private:
|
||||||
TEST_CASE(version);
|
TEST_CASE(version);
|
||||||
TEST_CASE(versionWithCfg);
|
TEST_CASE(versionWithCfg);
|
||||||
TEST_CASE(versionExclusive);
|
TEST_CASE(versionExclusive);
|
||||||
|
TEST_CASE(versionWithInvalidCfg);
|
||||||
TEST_CASE(onefile);
|
TEST_CASE(onefile);
|
||||||
TEST_CASE(onepath);
|
TEST_CASE(onepath);
|
||||||
TEST_CASE(optionwithoutfile);
|
TEST_CASE(optionwithoutfile);
|
||||||
|
@ -268,7 +270,9 @@ private:
|
||||||
TEST_CASE(showtimeEmpty);
|
TEST_CASE(showtimeEmpty);
|
||||||
TEST_CASE(showtimeInvalid);
|
TEST_CASE(showtimeInvalid);
|
||||||
TEST_CASE(errorlist);
|
TEST_CASE(errorlist);
|
||||||
|
TEST_CASE(errorlistWithCfg);
|
||||||
TEST_CASE(errorlistExclusive);
|
TEST_CASE(errorlistExclusive);
|
||||||
|
TEST_CASE(errorlistWithInvalidCfg);
|
||||||
TEST_CASE(ignorepathsnopath);
|
TEST_CASE(ignorepathsnopath);
|
||||||
#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
|
#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
|
||||||
TEST_CASE(exceptionhandling);
|
TEST_CASE(exceptionhandling);
|
||||||
|
@ -360,6 +364,8 @@ private:
|
||||||
TEST_CASE(cppcheckBuildDirExistent);
|
TEST_CASE(cppcheckBuildDirExistent);
|
||||||
TEST_CASE(cppcheckBuildDirNonExistent);
|
TEST_CASE(cppcheckBuildDirNonExistent);
|
||||||
TEST_CASE(cppcheckBuildDirEmpty);
|
TEST_CASE(cppcheckBuildDirEmpty);
|
||||||
|
|
||||||
|
TEST_CASE(invalidCppcheckCfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nooptions() {
|
void nooptions() {
|
||||||
|
@ -412,7 +418,7 @@ private:
|
||||||
|
|
||||||
void versionWithCfg() {
|
void versionWithCfg() {
|
||||||
REDIRECT;
|
REDIRECT;
|
||||||
ScopedFile file("cppcheck.cfg",
|
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
|
||||||
"{\n"
|
"{\n"
|
||||||
"\"productName\": \"The Product\""
|
"\"productName\": \"The Product\""
|
||||||
"}\n");
|
"}\n");
|
||||||
|
@ -433,6 +439,16 @@ private:
|
||||||
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
|
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void versionWithInvalidCfg() {
|
||||||
|
REDIRECT;
|
||||||
|
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
|
||||||
|
"{\n");
|
||||||
|
const char * const argv[] = {"cppcheck", "--version"};
|
||||||
|
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
|
||||||
|
ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: \n", logger->str());
|
||||||
|
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
void onefile() {
|
void onefile() {
|
||||||
REDIRECT;
|
REDIRECT;
|
||||||
const char * const argv[] = {"cppcheck", "file.cpp"};
|
const char * const argv[] = {"cppcheck", "file.cpp"};
|
||||||
|
@ -1690,11 +1706,19 @@ private:
|
||||||
const char * const argv[] = {"cppcheck", "--errorlist"};
|
const char * const argv[] = {"cppcheck", "--errorlist"};
|
||||||
ASSERT_EQUALS(CmdLineParser::Result::Exit, parser->parseFromArgs(2, argv));
|
ASSERT_EQUALS(CmdLineParser::Result::Exit, parser->parseFromArgs(2, argv));
|
||||||
ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger
|
ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger
|
||||||
ASSERT(startsWith(GET_REDIRECT_OUTPUT, "<?xml"));
|
ASSERT(startsWith(GET_REDIRECT_OUTPUT, ErrorMessage::getXMLHeader("")));
|
||||||
ASSERT(endsWith(GET_REDIRECT_OUTPUT, "</results>\n"));
|
ASSERT(endsWith(GET_REDIRECT_OUTPUT, "</results>\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test --errorlist with product name
|
void errorlistWithCfg() {
|
||||||
|
REDIRECT;
|
||||||
|
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
|
||||||
|
R"({"productName": "The Product"}\n)");
|
||||||
|
const char * const argv[] = {"cppcheck", "--errorlist"};
|
||||||
|
ASSERT_EQUALS(CmdLineParser::Result::Exit, parser->parseFromArgs(2, argv));
|
||||||
|
ASSERT_EQUALS("", logger->str()); // empty since it is logged via ErrorLogger
|
||||||
|
ASSERT(startsWith(GET_REDIRECT_OUTPUT, ErrorMessage::getXMLHeader("The Product")));
|
||||||
|
}
|
||||||
|
|
||||||
void errorlistExclusive() {
|
void errorlistExclusive() {
|
||||||
REDIRECT;
|
REDIRECT;
|
||||||
|
@ -1705,6 +1729,16 @@ private:
|
||||||
ASSERT(endsWith(GET_REDIRECT_OUTPUT, "</results>\n"));
|
ASSERT(endsWith(GET_REDIRECT_OUTPUT, "</results>\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void errorlistWithInvalidCfg() {
|
||||||
|
REDIRECT;
|
||||||
|
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
|
||||||
|
"{\n");
|
||||||
|
const char * const argv[] = {"cppcheck", "--errorlist"};
|
||||||
|
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
|
||||||
|
ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: \n", logger->str());
|
||||||
|
ASSERT_EQUALS("", GET_REDIRECT_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
void ignorepathsnopath() {
|
void ignorepathsnopath() {
|
||||||
REDIRECT;
|
REDIRECT;
|
||||||
const char * const argv[] = {"cppcheck", "-i"};
|
const char * const argv[] = {"cppcheck", "-i"};
|
||||||
|
@ -2309,6 +2343,15 @@ private:
|
||||||
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
|
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
|
||||||
ASSERT_EQUALS("cppcheck: error: Directory '' specified by --cppcheck-build-dir argument has to be existent.\n", logger->str());
|
ASSERT_EQUALS("cppcheck: error: Directory '' specified by --cppcheck-build-dir argument has to be existent.\n", logger->str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void invalidCppcheckCfg() {
|
||||||
|
REDIRECT;
|
||||||
|
ScopedFile file(Path::join(Path::getPathFromFilename(Path::getCurrentExecutablePath("")), "cppcheck.cfg"),
|
||||||
|
"{\n");
|
||||||
|
const char * const argv[] = {"cppcheck", "test.cpp"};
|
||||||
|
ASSERT_EQUALS(CmdLineParser::Result::Fail, parser->parseFromArgs(2, argv));
|
||||||
|
ASSERT_EQUALS("cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: \n", logger->str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestCmdlineParser)
|
REGISTER_TEST(TestCmdlineParser)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "errortypes.h"
|
#include "errortypes.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "fixture.h"
|
#include "fixture.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
class TestSettings : public TestFixture {
|
class TestSettings : public TestFixture {
|
||||||
public:
|
public:
|
||||||
|
@ -28,6 +29,7 @@ public:
|
||||||
private:
|
private:
|
||||||
void run() override {
|
void run() override {
|
||||||
TEST_CASE(simpleEnableGroup);
|
TEST_CASE(simpleEnableGroup);
|
||||||
|
TEST_CASE(loadCppcheckCfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void simpleEnableGroup() const {
|
void simpleEnableGroup() const {
|
||||||
|
@ -85,6 +87,128 @@ private:
|
||||||
ASSERT_EQUALS(false, group.isEnabled(Checks::missingInclude));
|
ASSERT_EQUALS(false, group.isEnabled(Checks::missingInclude));
|
||||||
ASSERT_EQUALS(false, group.isEnabled(Checks::internalCheck));
|
ASSERT_EQUALS(false, group.isEnabled(Checks::internalCheck));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadCppcheckCfg()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
"{}\n");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
"{\n");
|
||||||
|
ASSERT_EQUALS("not a valid JSON - syntax error at line 1 near: ", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"productName": ""}\n)");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
ASSERT_EQUALS("", s.cppcheckCfgProductName);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"productName": "product"}\n)");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
ASSERT_EQUALS("product", s.cppcheckCfgProductName);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"productName": 1}\n)");
|
||||||
|
ASSERT_EQUALS("'productName' is not a string", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"about": ""}\n)");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
ASSERT_EQUALS("", s.cppcheckCfgAbout);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"about": "about"}\n)");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
ASSERT_EQUALS("about", s.cppcheckCfgAbout);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"about": 1}\n)");
|
||||||
|
ASSERT_EQUALS("'about' is not a string", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"addons": []}\n)");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
ASSERT_EQUALS(0, s.addons.size());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"addons": 1}\n)");
|
||||||
|
ASSERT_EQUALS("'addons' is not an array", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"addons": ["addon"]}\n)");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
ASSERT_EQUALS(1, s.addons.size());
|
||||||
|
ASSERT_EQUALS("addon", *s.addons.cbegin());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"addons": [1]}\n)");
|
||||||
|
ASSERT_EQUALS("'addons' array entry is not a string", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"addons": []}\n)");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
ASSERT_EQUALS(0, s.addons.size());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"suppressions": 1}\n)");
|
||||||
|
ASSERT_EQUALS("'suppressions' is not an array", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"suppressions": ["id"]}\n)");
|
||||||
|
ASSERT_EQUALS("", s.loadCppcheckCfg());
|
||||||
|
ASSERT_EQUALS(1, s.nomsg.getSuppressions().size());
|
||||||
|
ASSERT_EQUALS("id", s.nomsg.getSuppressions().cbegin()->errorId);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"suppressions": [""]}\n)");
|
||||||
|
ASSERT_EQUALS("could not parse suppression '' - Failed to add suppression. No id.", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Settings s;
|
||||||
|
ScopedFile file("cppcheck.cfg",
|
||||||
|
R"({"suppressions": [1]}\n)");
|
||||||
|
ASSERT_EQUALS("'suppressions' array entry is not a string", s.loadCppcheckCfg());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: test with FILESDIR
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestSettings)
|
REGISTER_TEST(TestSettings)
|
||||||
|
|
Loading…
Reference in New Issue