Skip to content

Commit 5103ea1

Browse files
committed
improved determination if application is Premium / added TODOs
1 parent 4c0c68f commit 5103ea1

10 files changed

Lines changed: 92 additions & 29 deletions

File tree

cli/cmdlineparser.cpp

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,25 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
321321
// default to --check-level=normal from CLI for now
322322
mSettings.setCheckLevel(Settings::CheckLevel::normal);
323323

324+
// TODO: this is duplicated in gui/mainwindows.cpp
325+
{
326+
// only read cppcheck.cfg if the product name has not been set yet
327+
// this is hack so we can unit test this - should never happen in production
328+
if (mSettings.cppcheckCfgProductName.empty())
329+
{
330+
// load config to determine if we are premium - do not apply any other settings
331+
Settings s;
332+
s.exename = mSettings.exename;
333+
Suppressions supprs;
334+
// TODO: errorhandling
335+
Settings::loadCppcheckCfg(s, supprs, mSettings.debuglookup || mSettings.debuglookupConfig);
336+
mSettings.cppcheckCfgProductName = s.cppcheckCfgProductName;
337+
}
338+
mSettings.premium = startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
339+
}
340+
324341
if (argc <= 1) {
325-
printHelp();
342+
printHelp(mSettings.premium);
326343
return Result::Exit;
327344
}
328345

@@ -359,7 +376,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
359376

360377
// Print help
361378
if (std::strcmp(argv[i], "-h") == 0 || std::strcmp(argv[i], "--help") == 0) {
362-
printHelp();
379+
printHelp(mSettings.premium);
363380
return Result::Exit;
364381
}
365382

@@ -1084,7 +1101,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
10841101
}
10851102

10861103
// Special Cppcheck Premium options
1087-
else if ((std::strncmp(argv[i], "--premium=", 10) == 0 || std::strncmp(argv[i], "--premium-", 10) == 0) && isCppcheckPremium()) {
1104+
else if ((std::strncmp(argv[i], "--premium=", 10) == 0 || std::strncmp(argv[i], "--premium-", 10) == 0) && mSettings.premium) {
10881105
// valid options --premium=..
10891106
const std::set<std::string> valid{
10901107
"autosar",
@@ -1681,13 +1698,15 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
16811698
return Result::Success;
16821699
}
16831700

1684-
void CmdLineParser::printHelp() const
1701+
void CmdLineParser::printHelp(bool premium) const
16851702
{
1686-
const std::string manualUrl(isCppcheckPremium() ?
1687-
"https://cppcheck.sourceforge.io/manual.pdf" :
1688-
"https://files.cppchecksolutions.com/manual.pdf");
1703+
// TODO: fetch URL from config like product name?
1704+
const std::string manualUrl(premium ?
1705+
"https://files.cppchecksolutions.com/manual.pdf" :
1706+
"https://cppcheck.sourceforge.io/manual.pdf");
16891707

16901708
std::ostringstream oss;
1709+
// TODO: display product name
16911710
oss << "Cppcheck - A tool for static C/C++ code analysis\n"
16921711
"\n"
16931712
"Syntax:\n"
@@ -1888,7 +1907,7 @@ void CmdLineParser::printHelp() const
18881907
" --plist-output=<path>\n"
18891908
" Generate Clang-plist output files in folder.\n";
18901909

1891-
if (isCppcheckPremium()) {
1910+
if (premium) {
18921911
oss <<
18931912
" --premium=<option>\n"
18941913
" Coding standards:\n"
@@ -2071,6 +2090,7 @@ void CmdLineParser::printHelp() const
20712090
}
20722091

20732092
std::string CmdLineParser::getVersion() const {
2093+
// TODO: this should not contain the version - it should set the extraVersion
20742094
if (!mSettings.cppcheckCfgProductName.empty())
20752095
return mSettings.cppcheckCfgProductName;
20762096
const char * const extraVersion = CppCheck::extraVersion();
@@ -2079,12 +2099,6 @@ std::string CmdLineParser::getVersion() const {
20792099
return std::string("Cppcheck ") + CppCheck::version();
20802100
}
20812101

2082-
bool CmdLineParser::isCppcheckPremium() const {
2083-
if (mSettings.cppcheckCfgProductName.empty())
2084-
Settings::loadCppcheckCfg(mSettings, mSuppressions, mSettings.debuglookup || mSettings.debuglookupConfig);
2085-
return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
2086-
}
2087-
20882102
bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename, bool debug)
20892103
{
20902104
const Library::Error err = destination.load(basepath.c_str(), filename, debug);
@@ -2177,10 +2191,15 @@ bool CmdLineParser::loadAddons(Settings& settings)
21772191

21782192
bool CmdLineParser::loadCppcheckCfg()
21792193
{
2180-
if (!mSettings.cppcheckCfgProductName.empty())
2181-
return true;
2194+
if (!mSettings.settingsFiles.empty())
2195+
{
2196+
// should never happen - programming error
2197+
mLogger.printError("cppcheck.cfg has already been loaded from " + mSettings.settingsFiles[0]);
2198+
return false;
2199+
}
21822200
const std::string cfgErr = Settings::loadCppcheckCfg(mSettings, mSuppressions, mSettings.debuglookup || mSettings.debuglookupConfig);
21832201
if (!cfgErr.empty()) {
2202+
// TODO: log full path
21842203
mLogger.printError("could not load cppcheck.cfg - " + cfgErr);
21852204
return false;
21862205
}

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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) :
131131
mSelectLanguageActions(new QActionGroup(this)),
132132
mSelectReportActions(new QActionGroup(this))
133133
{
134+
// TODO: this is duplicated in cli/cmdlineparser.cpp
134135
{
135136
Settings tempSettings;
136137
tempSettings.exename = QCoreApplication::applicationFilePath().toStdString();
@@ -1087,6 +1088,8 @@ bool MainWindow::getCppcheckSettings(Settings& settings, Suppressions& supprs)
10871088
return false;
10881089
}
10891090

1091+
settings.premium = startsWith(settings.cppcheckCfgProductName, "Cppcheck Premium");
1092+
10901093
const auto cfgAddons = settings.addons;
10911094
settings.addons.clear();
10921095
for (const std::string& addon : cfgAddons) {
@@ -1750,6 +1753,7 @@ void MainWindow::formatAndSetTitle(const QString &text)
17501753
nameWithVersion += " (" + extraVersion + ")";
17511754
}
17521755

1756+
// TODO: should not contain the version
17531757
if (!mCppcheckCfgProductName.isEmpty())
17541758
nameWithVersion = mCppcheckCfgProductName;
17551759

@@ -2278,7 +2282,9 @@ void MainWindow::replyFinished(QNetworkReply *reply) {
22782282
const QString str = reply->readAll();
22792283
qDebug() << "Response: " << str;
22802284
if (reply->url().fileName() == "version.txt") {
2285+
// TODO: lacks extra version
22812286
QString nameWithVersion = QString("Cppcheck %1").arg(CppCheck::version());
2287+
// TODO: this should not contain the version
22822288
if (!mCppcheckCfgProductName.isEmpty())
22832289
nameWithVersion = mCppcheckCfgProductName;
22842290
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: 2 additions & 1 deletion
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
@@ -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
@@ -312,6 +312,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
312312
/** @brief plist output (--plist-output=&lt;dir&gt;) */
313313
std::string plistOutput;
314314

315+
/** @brief Are we Cppcheck Premium */
316+
bool premium{};
317+
315318
/** @brief Extra arguments for Cppcheck Premium addon */
316319
std::string premiumArgs;
317320

@@ -398,6 +401,9 @@ class CPPCHECKLIB WARN_UNUSED Settings {
398401

399402
SafeChecks safeChecks;
400403

404+
/** @brief the files we successfully loaded settings from */
405+
std::vector<std::string> settingsFiles;
406+
401407
SimpleEnableGroup<Severity> severity;
402408
SimpleEnableGroup<Certainty> certainty;
403409
SimpleEnableGroup<Checks> checks;

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

@@ -1701,6 +1702,26 @@ def test_cpp_probe_2(tmpdir):
17011702
assert_cppcheck(args, ec_exp=0, err_exp=[], out_exp=[])
17021703

17031704

1705+
def test_config_invalid(tmpdir):
1706+
# cppcheck.cfg needs to be next to executable
1707+
exe = shutil.copy2(__lookup_cppcheck_exe(), tmpdir)
1708+
shutil.copytree(os.path.join(os.path.dirname(__lookup_cppcheck_exe()), 'cfg'), os.path.join(tmpdir, 'cfg'))
1709+
1710+
test_file = os.path.join(tmpdir, 'test.c')
1711+
with open(test_file, 'wt'):
1712+
pass
1713+
1714+
config_file = os.path.join(tmpdir, 'cppcheck.cfg')
1715+
with open(config_file, 'wt'):
1716+
pass
1717+
1718+
exitcode, stdout, stderr, exe = cppcheck_ex([test_file], cwd=tmpdir, cppcheck_exe=exe)
1719+
assert exitcode == 1, stdout if stdout else stderr
1720+
assert stdout.splitlines() == [
1721+
'cppcheck: error: could not load cppcheck.cfg - not a valid JSON - syntax error at line 1 near: '
1722+
]
1723+
1724+
17041725
def test_checkers_report(tmpdir):
17051726
test_file = os.path.join(tmpdir, 'test.c')
17061727
with open(test_file, 'wt') as f:

test/cli/premium_test.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ def __copy_cppcheck_premium(tmpdir):
2626
{
2727
"addons": [],
2828
"productName": "NAME",
29-
"about": "NAME",
30-
"safety": true
29+
"about": "NAME"
3130
}
3231
""".replace('NAME', __PRODUCT_NAME))
3332

@@ -45,29 +44,29 @@ def test_misra_c_builtin_style_checks(tmpdir):
4544

4645
exe = __copy_cppcheck_premium(tmpdir)
4746

48-
exitcode, _, stderr = cppcheck(['--premium=autosar', '--xml', test_file], cppcheck_exe=exe)
47+
exitcode, _, stderr = cppcheck(['--premium=autosar', '--premium=safety', '--xml', test_file], cppcheck_exe=exe)
4948
assert exitcode == 0
5049
assert 'id="unusedVariable"' in stderr
5150
assert 'id="checkersReport"' in stderr
5251

53-
exitcode, _, stderr = cppcheck(['--premium=autosar', '--premium=safety-off', '--xml', test_file], cppcheck_exe=exe)
52+
exitcode, _, stderr = cppcheck(['--premium=autosar', '--xml', test_file], cppcheck_exe=exe)
5453
assert exitcode == 0
5554
assert 'id="unusedVariable"' in stderr
5655
assert 'id="checkersReport"' not in stderr
5756

58-
exitcode, _, stderr = cppcheck(['--xml-version=3', test_file], cppcheck_exe=exe)
57+
exitcode, _, stderr = cppcheck(['--xml-version=3', '--premium=safety', test_file], cppcheck_exe=exe)
5958
assert exitcode == 0
6059
assert '<safety/>' in stderr
6160

62-
exitcode, _, stderr = cppcheck(['--xml-version=3', '--premium=safety-off', test_file], cppcheck_exe=exe)
61+
exitcode, _, stderr = cppcheck(['--xml-version=3', test_file], cppcheck_exe=exe)
6362
assert exitcode == 0
6463
assert '<safety/>' not in stderr
6564

66-
exitcode, _, stderr = cppcheck(['--xml-version=3', '--inline-suppr', test_file], cppcheck_exe=exe)
65+
exitcode, _, stderr = cppcheck(['--xml-version=3', '--premium=safety', '--inline-suppr', test_file], cppcheck_exe=exe)
6766
assert exitcode == 0
6867
assert '<inline-suppr/>' in stderr
6968

70-
exitcode, _, stderr = cppcheck(['--xml-version=3', '--suppress=foo', test_file], cppcheck_exe=exe)
69+
exitcode, _, stderr = cppcheck(['--xml-version=3', '--premium=safety', '--suppress=foo', test_file], cppcheck_exe=exe)
7170
assert exitcode == 0
7271
assert '<suppression errorId="foo" inline="false" />' in stderr
7372

@@ -156,3 +155,13 @@ def test_invalid_license_retry(tmpdir):
156155

157156
_, _, stderr = cppcheck(args)
158157
assert 'Invalid license' not in stderr
158+
159+
160+
def test_help(tmpdir):
161+
exe = __copy_cppcheck_premium(tmpdir)
162+
163+
exitcode, stdout, _ = cppcheck(['--help'], cppcheck_exe=exe)
164+
assert exitcode == 0
165+
assert stdout.startswith('Cppcheck ') # check for product name - TODO: should be "Cppcheck Premium"
166+
assert '--premium=' in stdout, stdout # check for premium option
167+
assert 'cppchecksolutions.com' in stdout, stdout # check for premium help link

0 commit comments

Comments
 (0)