Skip to content

Commit 30e34e2

Browse files
authored
Fix #12389 (GUI: premiumaddon is not executed properly anymore) (#5923)
1 parent c521dcb commit 30e34e2

6 files changed

Lines changed: 98 additions & 29 deletions

File tree

gui/mainwindow.cpp

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,11 @@ void MainWindow::saveSettings() const
486486

487487
void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, const bool checkConfiguration)
488488
{
489+
QPair<bool,Settings> checkSettingsPair = getCppcheckSettings();
490+
if (!checkSettingsPair.first)
491+
return;
492+
Settings& checkSettings = checkSettingsPair.second;
493+
489494
clearResults();
490495

491496
mIsLogfileLoaded = false;
@@ -522,7 +527,6 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons
522527
checkLockDownUI(); // lock UI while checking
523528

524529
mUI->mResults->setCheckDirectory(checkPath);
525-
Settings checkSettings = getCppcheckSettings();
526530
checkSettings.force = false;
527531
checkSettings.checkLibrary = checkLibrary;
528532
checkSettings.checkConfiguration = checkConfiguration;
@@ -550,9 +554,14 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons
550554

551555
void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrary, const bool checkConfiguration)
552556
{
553-
if (files.isEmpty()) {
557+
if (files.isEmpty())
554558
return;
555-
}
559+
560+
QPair<bool, Settings> checkSettingsPair = getCppcheckSettings();
561+
if (!checkSettingsPair.first)
562+
return;
563+
Settings& checkSettings = checkSettingsPair.second;
564+
556565
clearResults();
557566

558567
mIsLogfileLoaded = false;
@@ -591,7 +600,6 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar
591600
checkLockDownUI(); // lock UI while checking
592601

593602
mUI->mResults->setCheckDirectory(checkPath);
594-
Settings checkSettings = getCppcheckSettings();
595603
checkSettings.checkLibrary = checkLibrary;
596604
checkSettings.checkConfiguration = checkConfiguration;
597605

@@ -614,6 +622,11 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar
614622

615623
void MainWindow::analyzeCode(const QString& code, const QString& filename)
616624
{
625+
const QPair<bool, Settings>& checkSettingsPair = getCppcheckSettings();
626+
if (!checkSettingsPair.first)
627+
return;
628+
const Settings& checkSettings = checkSettingsPair.second;
629+
617630
// Initialize dummy ThreadResult as ErrorLogger
618631
ThreadResult result;
619632
result.setFiles(QStringList(filename));
@@ -628,7 +641,7 @@ void MainWindow::analyzeCode(const QString& code, const QString& filename)
628641

629642
// Create CppCheck instance
630643
CppCheck cppcheck(result, true, nullptr);
631-
cppcheck.settings() = getCppcheckSettings();
644+
cppcheck.settings() = checkSettings;
632645

633646
// Check
634647
checkLockDownUI();
@@ -905,13 +918,12 @@ bool MainWindow::tryLoadLibrary(Library *library, const QString& filename)
905918
return true;
906919
}
907920

908-
void MainWindow::loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon)
921+
QString MainWindow::loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon)
909922
{
910-
QString addonFilePath = ProjectFile::getAddonFilePath(filesDir, addon);
911-
if (addonFilePath.isEmpty())
912-
return; // TODO: report an error
923+
const QString addonFilePath = fromNativePath(ProjectFile::getAddonFilePath(filesDir, addon));
913924

914-
addonFilePath.replace(QChar('\\'), QChar('/'));
925+
if (addonFilePath.isEmpty())
926+
return tr("File not found: '%1'").arg(addon);
915927

916928
picojson::object obj;
917929
obj["script"] = picojson::value(addonFilePath.toStdString());
@@ -929,42 +941,54 @@ void MainWindow::loadAddon(Settings &settings, const QString &filesDir, const QS
929941
obj["args"] = picojson::value(arg.toStdString());
930942
}
931943
}
932-
picojson::value json;
933-
json.set(std::move(obj));
934-
std::string json_str = json.serialize();
944+
945+
const std::string& json_str = picojson::value(obj).serialize();
935946

936947
AddonInfo addonInfo;
937-
addonInfo.getAddonInfo(json_str, settings.exename); // TODO: handle error
948+
const std::string errmsg = addonInfo.getAddonInfo(json_str, settings.exename);
949+
if (!errmsg.empty())
950+
return tr("Failed to load/setup addon %1: %2").arg(addon, QString::fromStdString(errmsg));
938951
settings.addonInfos.emplace_back(std::move(addonInfo));
939952

940-
settings.addons.emplace(std::move(json_str));
953+
settings.addons.emplace(json_str);
954+
955+
return "";
941956
}
942957

943-
Settings MainWindow::getCppcheckSettings()
958+
QPair<bool,Settings> MainWindow::getCppcheckSettings()
944959
{
945960
saveSettings(); // Save settings
946961

962+
Settings::terminate(true);
947963
Settings result;
948964

949965
result.exename = QCoreApplication::applicationFilePath().toStdString();
950966

951967
const bool std = tryLoadLibrary(&result.library, "std.cfg");
952-
if (!std)
953-
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"));
968+
if (!std) {
969+
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.\n\nAnalysis is aborted.").arg("std.cfg"));
970+
return {false, {}};
971+
}
954972

955973
const QString filesDir(getDataDir());
956974
const QString pythonCmd = fromNativePath(mSettings->value(SETTINGS_PYTHON_PATH).toString());
957975

958976
{
959977
const QString cfgErr = QString::fromStdString(result.loadCppcheckCfg());
960-
if (!cfgErr.isEmpty())
961-
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1 - %2").arg("cppcheck.cfg").arg(cfgErr));
978+
if (!cfgErr.isEmpty()) {
979+
QMessageBox::critical(this, tr("Error"), tr("Failed to load %1 - %2\n\nAnalysis is aborted.").arg("cppcheck.cfg").arg(cfgErr));
980+
return {false, {}};
981+
}
962982

963983
const auto cfgAddons = result.addons;
964984
result.addons.clear();
965985
for (const std::string& addon : cfgAddons) {
966986
// TODO: support addons which are a script and not a file
967-
loadAddon(result, filesDir, pythonCmd, QString::fromStdString(addon));
987+
const QString addonError = loadAddon(result, filesDir, pythonCmd, QString::fromStdString(addon));
988+
if (!addonError.isEmpty()) {
989+
QMessageBox::critical(this, tr("Error"), tr("%1\n\nAnalysis is aborted.").arg(addonError));
990+
return {false, {}};
991+
}
968992
}
969993
}
970994

@@ -1045,7 +1069,11 @@ Settings MainWindow::getCppcheckSettings()
10451069
result.checkUnknownFunctionReturn.insert(s.toStdString());
10461070

10471071
for (const QString& addon : mProjectFile->getAddons()) {
1048-
loadAddon(result, filesDir, pythonCmd, addon);
1072+
const QString addonError = loadAddon(result, filesDir, pythonCmd, addon);
1073+
if (!addonError.isEmpty()) {
1074+
QMessageBox::critical(this, tr("Error"), tr("%1\n\nAnalysis is aborted.").arg(addonError));
1075+
return {false, {}};
1076+
}
10491077
}
10501078

10511079
if (isCppcheckPremium()) {
@@ -1099,7 +1127,7 @@ Settings MainWindow::getCppcheckSettings()
10991127

11001128
Settings::terminate(false);
11011129

1102-
return result;
1130+
return {true, std::move(result)};
11031131
}
11041132

11051133
void MainWindow::analysisDone()
@@ -1223,6 +1251,11 @@ void MainWindow::reAnalyzeSelected(const QStringList& files)
12231251
if (mThread->isChecking())
12241252
return;
12251253

1254+
const QPair<bool, Settings> checkSettingsPair = getCppcheckSettings();
1255+
if (!checkSettingsPair.first)
1256+
return;
1257+
const Settings& checkSettings = checkSettingsPair.second;
1258+
12261259
// Clear details, statistics and progress
12271260
mUI->mResults->clear(false);
12281261
for (int i = 0; i < files.size(); ++i)
@@ -1242,7 +1275,6 @@ void MainWindow::reAnalyzeSelected(const QStringList& files)
12421275
// considered in "Modified Files Check" performed after "Selected Files Check"
12431276
// TODO: Should we store per file CheckStartTime?
12441277
QDateTime saveCheckStartTime = mThread->getCheckStartTime();
1245-
const Settings& checkSettings = getCppcheckSettings();
12461278
mThread->check(checkSettings);
12471279
mUI->mResults->setCheckSettings(checkSettings);
12481280
mThread->setCheckStartTime(saveCheckStartTime);
@@ -1254,6 +1286,11 @@ void MainWindow::reAnalyze(bool all)
12541286
if (files.empty())
12551287
return;
12561288

1289+
const QPair<bool, Settings>& checkSettingsPair = getCppcheckSettings();
1290+
if (!checkSettingsPair.first)
1291+
return;
1292+
const Settings& checkSettings = checkSettingsPair.second;
1293+
12571294
// Clear details, statistics and progress
12581295
mUI->mResults->clear(all);
12591296

@@ -1268,7 +1305,6 @@ void MainWindow::reAnalyze(bool all)
12681305
qDebug() << "Rechecking project file" << mProjectFile->getFilename();
12691306

12701307
mThread->setCheckFiles(all);
1271-
const Settings& checkSettings = getCppcheckSettings();
12721308
mThread->check(checkSettings);
12731309
mUI->mResults->setCheckSettings(checkSettings);
12741310
}

gui/mainwindow.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ private slots:
315315
*
316316
* @return Default cppcheck settings
317317
*/
318-
Settings getCppcheckSettings();
318+
QPair<bool, Settings> getCppcheckSettings();
319319

320320
/** @brief Load program settings */
321321
void loadSettings();
@@ -401,7 +401,7 @@ private slots:
401401
*/
402402
bool tryLoadLibrary(Library *library, const QString& filename);
403403

404-
void loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon);
404+
QString loadAddon(Settings &settings, const QString &filesDir, const QString &pythonCmd, const QString& addon);
405405

406406
/**
407407
* @brief Update project MRU items in File-menu.

gui/projectfile.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,9 @@ void ProjectFile::SafeChecks::saveToXml(QXmlStreamWriter &xmlWriter) const
11151115

11161116
QString ProjectFile::getAddonFilePath(QString filesDir, const QString &addon)
11171117
{
1118+
if (QFile(addon).exists())
1119+
return addon;
1120+
11181121
if (!filesDir.endsWith("/"))
11191122
filesDir += "/";
11201123

gui/test/projectfile/testprojectfile.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <QList>
3030
#include <QStringList>
31+
#include <QTemporaryDir>
3132
#include <QtTest>
3233

3334
// Mock...
@@ -116,4 +117,23 @@ void TestProjectFile::loadSimpleNoroot() const
116117
QCOMPARE(defines[0], QString("FOO"));
117118
}
118119

120+
void TestProjectFile::getAddonFilePath() const
121+
{
122+
QTemporaryDir tempdir;
123+
QVERIFY(tempdir.isValid());
124+
const QString filepath(tempdir.path() + "/addon.py");
125+
126+
QFile file(filepath);
127+
QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text));
128+
file.close();
129+
130+
// Relative path to addon
131+
QCOMPARE(ProjectFile::getAddonFilePath(tempdir.path(), "addon"), filepath);
132+
QCOMPARE(ProjectFile::getAddonFilePath(tempdir.path(), "not exist"), QString());
133+
134+
// Absolute path to addon
135+
QCOMPARE(ProjectFile::getAddonFilePath("/not/exist", filepath), filepath);
136+
QCOMPARE(ProjectFile::getAddonFilePath(tempdir.path(), filepath), filepath);
137+
}
138+
119139
QTEST_MAIN(TestProjectFile)

gui/test/projectfile/testprojectfile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ private slots:
2727
void loadSimple() const;
2828
void loadSimpleWithIgnore() const;
2929
void loadSimpleNoroot() const;
30+
31+
void getAddonFilePath() const;
3032
};

lib/addoninfo.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,11 @@ static std::string parseAddonInfo(AddonInfo& addoninfo, const picojson::value &j
105105
const auto& val = it->second;
106106
if (!val.is<std::string>())
107107
return "Loading " + fileName + " failed. 'executable' must be a string.";
108-
addoninfo.executable = getFullPath(val.get<std::string>(), fileName);
109-
return ""; // TODO: why bail out?
108+
const std::string e = val.get<std::string>();
109+
addoninfo.executable = getFullPath(e, fileName);
110+
if (addoninfo.executable.empty())
111+
addoninfo.executable = e;
112+
return ""; // <- do not load both "executable" and "script".
110113
}
111114
}
112115

@@ -157,6 +160,11 @@ std::string AddonInfo::getAddonInfo(const std::string &fileName, const std::stri
157160
std::ifstream fin(fileName);
158161
if (!fin.is_open())
159162
return "Failed to open " + fileName;
163+
if (name.empty()) {
164+
name = Path::fromNativeSeparators(fileName);
165+
if (name.find('/') != std::string::npos)
166+
name = name.substr(name.rfind('/') + 1);
167+
}
160168
picojson::value json;
161169
fin >> json;
162170
return parseAddonInfo(*this, json, fileName, exename);

0 commit comments

Comments
 (0)