Skip to content

Commit 2d1af4a

Browse files
committed
improved determination if application is Premium / added TODOs
1 parent fa0189b commit 2d1af4a

12 files changed

Lines changed: 175 additions & 78 deletions

cli/cmdlineparser.cpp

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,37 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
324324
// default to --check-level=normal from CLI for now
325325
mSettings.setCheckLevel(Settings::CheckLevel::normal);
326326

327+
// read --debug-lookup early so the option is available for the cppcheck.cfg loading
328+
for (int i = 1; i < argc; i++) {
329+
// Show debug warnings for lookup for configuration files
330+
if (std::strcmp(argv[i], "--debug-lookup") == 0)
331+
mSettings.debuglookup = true;
332+
333+
else if (std::strncmp(argv[i], "--debug-lookup=", 15) == 0) {
334+
const std::string lookup = argv[i] + 15;
335+
if (lookup == "all")
336+
mSettings.debuglookup = true;
337+
else if (lookup == "addon")
338+
mSettings.debuglookupAddon = true;
339+
else if (lookup == "config")
340+
mSettings.debuglookupConfig = true;
341+
else if (lookup == "library")
342+
mSettings.debuglookupLibrary = true;
343+
else if (lookup == "platform")
344+
mSettings.debuglookupPlatform = true;
345+
else
346+
{
347+
mLogger.printError("unknown lookup '" + lookup + "'");
348+
return Result::Fail;
349+
}
350+
}
351+
}
352+
353+
if (!loadCppcheckCfg())
354+
return Result::Fail;
355+
327356
if (argc <= 1) {
328-
printHelp();
357+
printHelp(mSettings.premium);
329358
return Result::Exit;
330359
}
331360

@@ -349,8 +378,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
349378

350379
// print all possible error messages..
351380
if (std::strcmp(argv[i], "--errorlist") == 0) {
352-
if (!loadCppcheckCfg())
353-
return Result::Fail;
354381
{
355382
XMLErrorMessagesLogger xmlLogger;
356383
std::cout << ErrorMessage::getXMLHeader(mSettings.cppcheckCfgProductName, 2);
@@ -362,7 +389,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
362389

363390
// Print help
364391
if (std::strcmp(argv[i], "-h") == 0 || std::strcmp(argv[i], "--help") == 0) {
365-
printHelp();
392+
printHelp(mSettings.premium);
366393
return Result::Exit;
367394
}
368395

@@ -374,8 +401,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
374401
}
375402

376403
if (std::strcmp(argv[i], "--version") == 0) {
377-
if (!loadCppcheckCfg())
378-
return Result::Fail;
379404
const std::string version = getVersion();
380405
mLogger.printRaw(version); // TODO: should not include newline
381406
return Result::Exit;
@@ -614,28 +639,11 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
614639
std::strcmp(argv[i], "--debug-normal") == 0)
615640
debug = true;
616641

617-
// Show debug warnings for lookup for configuration files
618642
else if (std::strcmp(argv[i], "--debug-lookup") == 0)
619-
mSettings.debuglookup = true;
643+
continue; // already handled above
620644

621-
else if (std::strncmp(argv[i], "--debug-lookup=", 15) == 0) {
622-
const std::string lookup = argv[i] + 15;
623-
if (lookup == "all")
624-
mSettings.debuglookup = true;
625-
else if (lookup == "addon")
626-
mSettings.debuglookupAddon = true;
627-
else if (lookup == "config")
628-
mSettings.debuglookupConfig = true;
629-
else if (lookup == "library")
630-
mSettings.debuglookupLibrary = true;
631-
else if (lookup == "platform")
632-
mSettings.debuglookupPlatform = true;
633-
else
634-
{
635-
mLogger.printError("unknown lookup '" + lookup + "'");
636-
return Result::Fail;
637-
}
638-
}
645+
else if (std::strncmp(argv[i], "--debug-lookup=", 15) == 0)
646+
continue; // already handled above
639647

640648
// Flag used for various purposes during debugging
641649
else if (std::strcmp(argv[i], "--debug-simplified") == 0)
@@ -1087,7 +1095,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
10871095
}
10881096

10891097
// Special Cppcheck Premium options
1090-
else if ((std::strncmp(argv[i], "--premium=", 10) == 0 || std::strncmp(argv[i], "--premium-", 10) == 0) && isCppcheckPremium()) {
1098+
else if ((std::strncmp(argv[i], "--premium=", 10) == 0 || std::strncmp(argv[i], "--premium-", 10) == 0) && mSettings.premium) {
10911099
// valid options --premium=..
10921100
const std::set<std::string> valid{
10931101
"autosar",
@@ -1148,7 +1156,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
11481156

11491157
mSettings.checkAllConfigurations = false; // Can be overridden with --max-configs or --force
11501158
std::string projectFile = argv[i]+10;
1151-
projectType = project.import(projectFile, &mSettings, &mSuppressions, isCppcheckPremium());
1159+
projectType = project.import(projectFile, &mSettings, &mSuppressions, mSettings.premium);
11521160
if (projectType == ImportProject::Type::CPPCHECK_GUI) {
11531161
for (const std::string &lib : project.guiProject.libraries)
11541162
mSettings.libraries.emplace_back(lib);
@@ -1561,9 +1569,6 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
15611569
}
15621570
}
15631571

1564-
if (!loadCppcheckCfg())
1565-
return Result::Fail;
1566-
15671572
// TODO: bail out?
15681573
if (!executorAuto && mSettings.useSingleJob())
15691574
mLogger.printMessage("'--executor' has no effect as only a single job will be used.");
@@ -1687,13 +1692,15 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
16871692
return Result::Success;
16881693
}
16891694

1690-
void CmdLineParser::printHelp() const
1695+
void CmdLineParser::printHelp(bool premium) const
16911696
{
1692-
const std::string manualUrl(isCppcheckPremium() ?
1693-
"https://cppcheck.sourceforge.io/manual.pdf" :
1694-
"https://files.cppchecksolutions.com/manual.pdf");
1697+
// TODO: fetch URL from config like product name?
1698+
const std::string manualUrl(premium ?
1699+
"https://files.cppchecksolutions.com/manual.pdf" :
1700+
"https://cppcheck.sourceforge.io/manual.pdf");
16951701

16961702
std::ostringstream oss;
1703+
// TODO: display product name
16971704
oss << "Cppcheck - A tool for static C/C++ code analysis\n"
16981705
"\n"
16991706
"Syntax:\n"
@@ -1894,7 +1901,7 @@ void CmdLineParser::printHelp() const
18941901
" --plist-output=<path>\n"
18951902
" Generate Clang-plist output files in folder.\n";
18961903

1897-
if (isCppcheckPremium()) {
1904+
if (premium) {
18981905
oss <<
18991906
" --premium=<option>\n"
19001907
" Coding standards:\n"
@@ -2077,6 +2084,7 @@ void CmdLineParser::printHelp() const
20772084
}
20782085

20792086
std::string CmdLineParser::getVersion() const {
2087+
// TODO: this should not contain the version - it should set the extraVersion
20802088
if (!mSettings.cppcheckCfgProductName.empty())
20812089
return mSettings.cppcheckCfgProductName;
20822090
const char * const extraVersion = CppCheck::extraVersion();
@@ -2085,12 +2093,6 @@ std::string CmdLineParser::getVersion() const {
20852093
return std::string("Cppcheck ") + CppCheck::version();
20862094
}
20872095

2088-
bool CmdLineParser::isCppcheckPremium() const {
2089-
if (mSettings.cppcheckCfgProductName.empty())
2090-
Settings::loadCppcheckCfg(mSettings, mSuppressions, mSettings.debuglookup || mSettings.debuglookupConfig);
2091-
return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
2092-
}
2093-
20942096
bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename, bool debug)
20952097
{
20962098
const Library::Error err = destination.load(basepath.c_str(), filename, debug);
@@ -2183,13 +2185,19 @@ bool CmdLineParser::loadAddons(Settings& settings)
21832185

21842186
bool CmdLineParser::loadCppcheckCfg()
21852187
{
2186-
if (!mSettings.cppcheckCfgProductName.empty())
2187-
return true;
2188+
if (!mSettings.settingsFiles.empty())
2189+
{
2190+
// should never happen - programming error
2191+
mLogger.printError("cppcheck.cfg has already been loaded from " + mSettings.settingsFiles[0]);
2192+
return false;
2193+
}
21882194
const std::string cfgErr = Settings::loadCppcheckCfg(mSettings, mSuppressions, mSettings.debuglookup || mSettings.debuglookupConfig);
21892195
if (!cfgErr.empty()) {
2196+
// TODO: log full path
21902197
mLogger.printError("could not load cppcheck.cfg - " + cfgErr);
21912198
return false;
21922199
}
2200+
mSettings.premium = startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
21932201
return true;
21942202
}
21952203

cli/cmdlineparser.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,9 @@ class CmdLineParser {
124124
/**
125125
* Print help text to the console.
126126
*/
127-
void printHelp() const;
127+
void printHelp(bool premium) const;
128128

129129
private:
130-
bool isCppcheckPremium() const;
131-
132130
template<typename T>
133131
bool parseNumberArg(const char* const arg, std::size_t offset, T& num, bool mustBePositive = false)
134132
{

gui/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ static void ShowUsage()
124124

125125
static void ShowVersion()
126126
{
127+
// TODO: should only *not* show a dialog when we are on a commnd-line
127128
#if defined(_WIN32)
128129
AboutDialog *dlg = new AboutDialog(CppCheck::version(), CppCheck::extraVersion(), 0);
129130
dlg->exec();

gui/mainwindow.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,8 @@ bool MainWindow::getCppcheckSettings(Settings& settings, Suppressions& supprs)
10911091
return false;
10921092
}
10931093

1094+
settings.premium = startsWith(settings.cppcheckCfgProductName, "Cppcheck Premium");
1095+
10941096
const auto cfgAddons = settings.addons;
10951097
settings.addons.clear();
10961098
for (const std::string& addon : cfgAddons) {
@@ -1754,6 +1756,7 @@ void MainWindow::formatAndSetTitle(const QString &text)
17541756
nameWithVersion += " (" + extraVersion + ")";
17551757
}
17561758

1759+
// TODO: should not contain the version
17571760
if (!mCppcheckCfgProductName.isEmpty())
17581761
nameWithVersion = mCppcheckCfgProductName;
17591762

@@ -2282,7 +2285,9 @@ void MainWindow::replyFinished(QNetworkReply *reply) {
22822285
const QString str = reply->readAll();
22832286
qDebug() << "Response: " << str;
22842287
if (reply->url().fileName() == "version.txt") {
2288+
// TODO: lacks extra version
22852289
QString nameWithVersion = QString("Cppcheck %1").arg(CppCheck::version());
2290+
// TODO: this should not contain the version
22862291
if (!mCppcheckCfgProductName.isEmpty())
22872292
nameWithVersion = mCppcheckCfgProductName;
22882293
const int appVersion = getVersion(nameWithVersion);

gui/xmlreportv2.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ void XmlReportV2::writeHeader()
9494
{
9595
const auto nameAndVersion = Settings::getNameAndVersion(mProductName.toStdString());
9696
const QString name = QString::fromStdString(nameAndVersion.first);
97+
// TODO: lacks extraVersion
9798
const QString version = nameAndVersion.first.empty() ? CppCheck::version() : QString::fromStdString(nameAndVersion.second);
9899

99100
mXmlWriter->setAutoFormatting(true);

lib/errorlogger.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ std::string ErrorMessage::getXMLHeader(std::string productName, int xmlVersion)
437437
{
438438
const auto nameAndVersion = Settings::getNameAndVersion(productName);
439439
productName = nameAndVersion.first;
440+
// TODO: lacks extra version
440441
const std::string version = nameAndVersion.first.empty() ? CppCheck::version() : nameAndVersion.second;
441442

442443
tinyxml2::XMLPrinter printer;

lib/settings.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ Settings::Settings()
6767

6868
std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppressions, bool debug)
6969
{
70-
// TODO: this always needs to be run *after* the Settings has been filled
7170
static const std::string cfgFilename = "cppcheck.cfg";
7271
std::string fileName;
7372
#ifdef FILESDIR
@@ -82,7 +81,7 @@ std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppress
8281
// cppcheck-suppress knownConditionTrueFalse
8382
if (fileName.empty()) {
8483
// TODO: make sure that exename is set
85-
fileName = Path::getPathFromFilename(settings.exename) + cfgFilename;
84+
fileName = Path::join(Path::getPathFromFilename(settings.exename), cfgFilename);
8685
if (debug)
8786
std::cout << "looking for '" << fileName << "'" << std::endl;
8887
if (!Path::isFile(fileName))
@@ -167,6 +166,8 @@ std::string Settings::loadCppcheckCfg(Settings& settings, Suppressions& suppress
167166
}
168167
}
169168

169+
settings.settingsFiles.emplace_back(std::move(fileName));
170+
170171
return "";
171172
}
172173

lib/settings.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
318318
/** @brief plist output (--plist-output=&lt;dir&gt;) */
319319
std::string plistOutput;
320320

321+
/** @brief Are we Cppcheck Premium */
322+
bool premium{};
323+
321324
/** @brief Extra arguments for Cppcheck Premium addon */
322325
std::string premiumArgs;
323326

@@ -405,6 +408,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
405408

406409
SafeChecks safeChecks;
407410

411+
/** @brief the files we successfully loaded settings from */
412+
std::vector<std::string> settingsFiles;
413+
408414
SimpleEnableGroup<Severity> severity;
409415
SimpleEnableGroup<Certainty> certainty;
410416
SimpleEnableGroup<Checks> checks;

test/cli/lookup_test.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,7 @@ def test_config_lookup(tmpdir):
858858
exitcode, stdout, stderr, exe = cppcheck_ex(['--debug-lookup=config', test_file], cwd=tmpdir, cppcheck_exe=tmp_cppcheck_exe)
859859
exepath = os.path.dirname(exe)
860860
exepath_sep = exepath + os.path.sep
861+
exepath_sep = exepath_sep.replace('\\', '/')
861862
assert exitcode == 0, stdout if stdout else stderr
862863
lines = stdout.splitlines()
863864
assert lines == [
@@ -874,6 +875,7 @@ def test_config_lookup_notfound(tmpdir):
874875
exitcode, stdout, stderr, exe = cppcheck_ex(['--debug-lookup=config', test_file])
875876
exepath = os.path.dirname(exe)
876877
exepath_sep = exepath + os.path.sep
878+
exepath_sep = exepath_sep.replace('\\', '/')
877879
assert exitcode == 0, stdout if stdout else stderr
878880
lines = stdout.splitlines()
879881
assert lines == [
@@ -902,6 +904,7 @@ def test_config_invalid(tmpdir):
902904
exitcode, stdout, stderr, exe = cppcheck_ex(['--debug-lookup=config', test_file], cwd=tmpdir, cppcheck_exe=tmp_cppcheck_exe)
903905
exepath = os.path.dirname(exe)
904906
exepath_sep = exepath + os.path.sep
907+
exepath_sep = exepath_sep.replace('\\', '/')
905908
assert exitcode == 1, stdout if stdout else stderr
906909
lines = stdout.splitlines()
907910
assert lines == [

test/cli/other_test.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
import glob
88
import json
99
import subprocess
10+
import shutil
1011

11-
from testutils import cppcheck, assert_cppcheck
12+
from testutils import cppcheck, assert_cppcheck, cppcheck_ex, __lookup_cppcheck_exe
1213
from xml.etree import ElementTree
1314

1415

@@ -1722,6 +1723,26 @@ def test_cpp_probe_2(tmpdir):
17221723
assert_cppcheck(args, ec_exp=0, err_exp=[], out_exp=[])
17231724

17241725

1726+
def test_config_invalid(tmpdir):
1727+
# cppcheck.cfg needs to be next to executable
1728+
exe = shutil.copy2(__lookup_cppcheck_exe(), tmpdir)
1729+
shutil.copytree(os.path.join(os.path.dirname(__lookup_cppcheck_exe()), 'cfg'), os.path.join(tmpdir, 'cfg'))
1730+
1731+
test_file = os.path.join(tmpdir, 'test.c')
1732+
with open(test_file, 'wt'):
1733+
pass
1734+
1735+
config_file = os.path.join(tmpdir, 'cppcheck.cfg')
1736+
with open(config_file, 'wt'):
1737+
pass
1738+
1739+
exitcode, stdout, stderr, exe = cppcheck_ex([test_file], cwd=tmpdir, cppcheck_exe=exe)
1740+
assert exitcode == 1, stdout if stdout else stderr
1741+
assert stdout.splitlines() == [
1742+
'cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: '
1743+
]
1744+
1745+
17251746
def test_checkers_report(tmpdir):
17261747
test_file = os.path.join(tmpdir, 'test.c')
17271748
with open(test_file, 'wt') as f:

0 commit comments

Comments
 (0)