Fixed #9723 (GUI: inline suppressions does not work for addons)
This commit is contained in:
parent
d0e2fd240b
commit
547d1b158e
|
@ -269,75 +269,6 @@ void CheckThread::runAddonsAndTools(const ImportProject::FileSettings *fileSetti
|
|||
}
|
||||
|
||||
parseClangErrors(addon, fileName, errout);
|
||||
} else {
|
||||
const QString python = CheckThread::pythonCmd();
|
||||
if (python.isEmpty())
|
||||
continue;
|
||||
|
||||
const QString addonFilePath = CheckThread::getAddonFilePath(mDataDir, addon + ".py");
|
||||
if (addonFilePath.isEmpty())
|
||||
continue;
|
||||
|
||||
if (dumpFile.isEmpty()) {
|
||||
const std::string buildDir = mCppcheck.settings().buildDir;
|
||||
mCppcheck.settings().buildDir.clear();
|
||||
mCppcheck.settings().dump = true;
|
||||
if (!buildDir.empty()) {
|
||||
mCppcheck.settings().dumpFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir, fileName.toStdString(), fileSettings ? fileSettings->cfg : std::string()) + ".dump";
|
||||
dumpFile = QString::fromStdString(mCppcheck.settings().dumpFile);
|
||||
} else {
|
||||
dumpFile = fileName + ".dump";
|
||||
}
|
||||
if (fileSettings)
|
||||
mCppcheck.check(*fileSettings);
|
||||
else
|
||||
mCppcheck.check(fileName.toStdString());
|
||||
mCppcheck.settings().dump = false;
|
||||
mCppcheck.settings().dumpFile.clear();
|
||||
mCppcheck.settings().buildDir = buildDir;
|
||||
}
|
||||
|
||||
QStringList args;
|
||||
args << addonFilePath << "--cli" << dumpFile;
|
||||
if (addon == "misra" && !mMisraFile.isEmpty() && QFileInfo(mMisraFile).exists()) {
|
||||
if (mMisraFile.endsWith(".pdf", Qt::CaseInsensitive))
|
||||
args << "--misra-pdf=" + mMisraFile;
|
||||
else
|
||||
args << "--rule-texts=" + mMisraFile;
|
||||
}
|
||||
qDebug() << python << args;
|
||||
|
||||
QProcess process;
|
||||
QProcessEnvironment env = process.processEnvironment();
|
||||
if (!env.contains("PYTHONHOME") && !python.startsWith("python")) {
|
||||
env.insert("PYTHONHOME", QFileInfo(python).canonicalPath());
|
||||
process.setProcessEnvironment(env);
|
||||
}
|
||||
process.start(python, args);
|
||||
if (!process.waitForFinished()) {
|
||||
const QString errMsg("ERROR: Process '" + python + " " + args.join(" ") +
|
||||
"' did not finish successfully: " + process.errorString());
|
||||
qWarning() << errMsg;
|
||||
mResult.reportOut(errMsg.toStdString());
|
||||
}
|
||||
const QByteArray errout = process.readAllStandardError();
|
||||
if (process.exitCode() != 0 && !errout.isEmpty()) {
|
||||
const QString errMsg("ERROR: Process '" + python + " " + args.join(" ") +
|
||||
"' failed with error code " +
|
||||
QString::number(process.exitCode()) + ": '" +
|
||||
process.errorString() +
|
||||
"'\nError output: " + errout);
|
||||
qWarning() << errMsg;
|
||||
mResult.reportOut(errMsg.toStdString());
|
||||
}
|
||||
const QString output(process.readAllStandardOutput());
|
||||
QFile f(dumpFile + '-' + addon + "-results");
|
||||
if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&f);
|
||||
out << output;
|
||||
f.close();
|
||||
}
|
||||
parseAddonErrors(output, addon);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,47 +283,6 @@ void CheckThread::stop()
|
|||
mCppcheck.terminate();
|
||||
}
|
||||
|
||||
void CheckThread::parseAddonErrors(QString err, const QString &tool)
|
||||
{
|
||||
Q_UNUSED(tool)
|
||||
QTextStream in(&err, QIODevice::ReadOnly);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
if (!line.startsWith("{"))
|
||||
continue;
|
||||
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(line.toLocal8Bit());
|
||||
const QJsonObject obj = doc.object();
|
||||
|
||||
/*
|
||||
msg = { 'file': location.file,
|
||||
'linenr': location.linenr,
|
||||
'column': location.column,
|
||||
'severity': severity,
|
||||
'message': message,
|
||||
'addon': addon,
|
||||
'errorId': errorId,
|
||||
'extra': extra}
|
||||
*/
|
||||
|
||||
const std::string &filename = obj["file"].toString().toStdString();
|
||||
const int lineNumber = obj["linenr"].toInt();
|
||||
const int column = obj["column"].toInt();
|
||||
const std::string severity = obj["severity"].toString().toStdString();
|
||||
const std::string message = obj["message"].toString().toStdString();
|
||||
const std::string id = (obj["addon"].toString() + "-" + obj["errorId"].toString()).toStdString();
|
||||
|
||||
std::list<ErrorLogger::ErrorMessage::FileLocation> callstack;
|
||||
callstack.push_back(ErrorLogger::ErrorMessage::FileLocation(filename, lineNumber, column));
|
||||
ErrorLogger::ErrorMessage errmsg(callstack, filename, Severity::fromString(severity), message, id, false);
|
||||
|
||||
if (isSuppressed(errmsg.toSuppressionsErrorMessage()))
|
||||
continue;
|
||||
|
||||
mResult.reportErr(errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckThread::parseClangErrors(const QString &tool, const QString &file0, QString err)
|
||||
{
|
||||
QList<ErrorItem> errorItems;
|
||||
|
@ -548,45 +438,3 @@ QString CheckThread::clangTidyCmd()
|
|||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString CheckThread::pythonCmd()
|
||||
{
|
||||
QString path = QSettings().value(SETTINGS_PYTHON_PATH).toString();
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
|
||||
path = "python";
|
||||
#ifdef Q_OS_WIN
|
||||
path += ".exe";
|
||||
#endif
|
||||
|
||||
QProcess process;
|
||||
process.start(path, QStringList() << "--version");
|
||||
process.waitForFinished();
|
||||
if (process.exitCode() == 0)
|
||||
return path;
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString CheckThread::getAddonFilePath(const QString &dataDir, const QString &addonFile)
|
||||
{
|
||||
const QStringList paths = QStringList() << "/" << "/addons/" << "/../addons/";
|
||||
|
||||
if (!dataDir.isEmpty()) {
|
||||
foreach (const QString p, paths) {
|
||||
const QString filePath(dataDir + p + addonFile);
|
||||
if (QFileInfo(filePath).exists())
|
||||
return filePath;
|
||||
}
|
||||
}
|
||||
|
||||
const QString appPath = QApplication::applicationDirPath();
|
||||
foreach (const QString p, paths) {
|
||||
const QString filePath(appPath + p + addonFile);
|
||||
if (QFileInfo(filePath).exists())
|
||||
return filePath;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
|
|
@ -57,10 +57,6 @@ public:
|
|||
mAddonsAndTools = addonsAndTools;
|
||||
}
|
||||
|
||||
void setMisraFile(const QString &misraFile) {
|
||||
mMisraFile = misraFile;
|
||||
}
|
||||
|
||||
void setDataDir(const QString &dataDir) {
|
||||
mDataDir = dataDir;
|
||||
}
|
||||
|
@ -93,18 +89,6 @@ public:
|
|||
*/
|
||||
static QString clangTidyCmd();
|
||||
|
||||
/**
|
||||
* Determine command to run python
|
||||
* \return Command to run python, empty if it is not found
|
||||
*/
|
||||
static QString pythonCmd();
|
||||
|
||||
/**
|
||||
* Look for addon and return path
|
||||
* \return path to addon if found, empty if it is not found
|
||||
*/
|
||||
static QString getAddonFilePath(const QString &dataDir, const QString &addonFile);
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
|
@ -144,7 +128,6 @@ protected:
|
|||
private:
|
||||
void runAddonsAndTools(const ImportProject::FileSettings *fileSettings, const QString &fileName);
|
||||
|
||||
void parseAddonErrors(QString err, const QString &tool);
|
||||
void parseClangErrors(const QString &tool, const QString &file0, QString err);
|
||||
|
||||
bool isSuppressed(const Suppressions::ErrorMessage &errorMessage) const;
|
||||
|
@ -155,7 +138,6 @@ private:
|
|||
QString mDataDir;
|
||||
QStringList mClangIncludePaths;
|
||||
QList<Suppressions::Suppression> mSuppressions;
|
||||
QString mMisraFile;
|
||||
};
|
||||
/// @}
|
||||
#endif // CHECKTHREAD_H
|
||||
|
|
|
@ -451,7 +451,7 @@ void MainWindow::doAnalyzeProject(ImportProject p, const bool checkLibrary, cons
|
|||
|
||||
//mThread->SetanalyzeProject(true);
|
||||
if (mProjectFile) {
|
||||
mThread->setAddonsAndTools(mProjectFile->getAddonsAndTools(), mSettings->value(SETTINGS_MISRA_FILE).toString());
|
||||
mThread->setAddonsAndTools(mProjectFile->getAddonsAndTools());
|
||||
QString clangHeaders = mSettings->value(SETTINGS_VS_INCLUDE_PATHS).toString();
|
||||
mThread->setClangIncludePaths(clangHeaders.split(";"));
|
||||
mThread->setSuppressions(mProjectFile->getSuppressions());
|
||||
|
@ -494,7 +494,7 @@ void MainWindow::doAnalyzeFiles(const QStringList &files, const bool checkLibrar
|
|||
|
||||
mThread->setFiles(fileNames);
|
||||
if (mProjectFile && !checkConfiguration)
|
||||
mThread->setAddonsAndTools(mProjectFile->getAddonsAndTools(), mSettings->value(SETTINGS_MISRA_FILE).toString());
|
||||
mThread->setAddonsAndTools(mProjectFile->getAddonsAndTools());
|
||||
mThread->setSuppressions(mProjectFile ? mProjectFile->getSuppressions() : QList<Suppressions::Suppression>());
|
||||
QDir inf(mCurrentDirectory);
|
||||
const QString checkPath = inf.canonicalPath();
|
||||
|
@ -916,6 +916,30 @@ Settings MainWindow::getCppcheckSettings()
|
|||
result.safeChecks.externalVariables = mProjectFile->safeChecks.externalVariables;
|
||||
foreach (QString s, mProjectFile->getCheckUnknownFunctionReturn())
|
||||
result.checkUnknownFunctionReturn.insert(s.toStdString());
|
||||
|
||||
QString filesDir(getDataDir(mSettings));
|
||||
const QString pythonCmd = mSettings->value(SETTINGS_PYTHON_PATH).toString();
|
||||
foreach (QString addon, mProjectFile->getAddons()) {
|
||||
QString addonFilePath = ProjectFile::getAddonFilePath(filesDir, addon);
|
||||
if (addonFilePath.isEmpty())
|
||||
continue;
|
||||
|
||||
QString json;
|
||||
json += "{ \"script\":\"" + addonFilePath + "\"";
|
||||
if (!pythonCmd.isEmpty())
|
||||
json += ", \"python\":\"" + pythonCmd + "\"";
|
||||
QString misraFile = mSettings->value(SETTINGS_MISRA_FILE).toString();
|
||||
if (addon == "misra" && !misraFile.isEmpty()) {
|
||||
QString arg;
|
||||
if (misraFile.endsWith(".pdf", Qt::CaseInsensitive))
|
||||
arg = "--misra-pdf=" + misraFile;
|
||||
else
|
||||
arg = "--rule-texts=" + misraFile;
|
||||
json += ", \"args\":[\"" + arg + "\"]";
|
||||
}
|
||||
json += " }";
|
||||
result.addons.push_back(json.toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
// Include directories (and files) are searched in listed order.
|
||||
|
@ -1518,7 +1542,7 @@ void MainWindow::analyzeProject(const ProjectFile *projectFile, const bool check
|
|||
|
||||
QDir::setCurrent(inf.absolutePath());
|
||||
|
||||
mThread->setAddonsAndTools(projectFile->getAddonsAndTools(), mSettings->value(SETTINGS_MISRA_FILE).toString());
|
||||
mThread->setAddonsAndTools(projectFile->getAddonsAndTools());
|
||||
mUI.mResults->setTags(projectFile->getTags());
|
||||
|
||||
// If the root path is not given or is not "current dir", use project
|
||||
|
|
|
@ -995,3 +995,21 @@ void ProjectFile::SafeChecks::saveToXml(QXmlStreamWriter &xmlWriter) const
|
|||
}
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
QString ProjectFile::getAddonFilePath(QString filesDir, QString addon)
|
||||
{
|
||||
if (!filesDir.endsWith("/"))
|
||||
filesDir += "/";
|
||||
|
||||
QStringList searchPaths;
|
||||
searchPaths << filesDir << (filesDir + "addons/") << (filesDir + "../addons/");
|
||||
|
||||
foreach (QString path, searchPaths) {
|
||||
QString f = path + addon + ".py";
|
||||
if (QFile(f).exists())
|
||||
return f;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
|
|
@ -167,6 +167,8 @@ public:
|
|||
return mAddons;
|
||||
}
|
||||
|
||||
static QString getAddonFilePath(QString filesDir, QString addon);
|
||||
|
||||
/**
|
||||
* @brief Get list of addons and tools.
|
||||
* @return list of addons and tools.
|
||||
|
|
|
@ -234,7 +234,7 @@ static void updateAddonCheckBox(QCheckBox *cb, const ProjectFile *projectFile, c
|
|||
{
|
||||
if (projectFile)
|
||||
cb->setChecked(projectFile->getAddons().contains(addon));
|
||||
if (CheckThread::getAddonFilePath(dataDir, addon + ".py").isEmpty()) {
|
||||
if (ProjectFile::getAddonFilePath(dataDir, addon).isEmpty()) {
|
||||
cb->setEnabled(false);
|
||||
cb->setText(cb->text() + QObject::tr(" (Not found)"));
|
||||
}
|
||||
|
|
|
@ -94,7 +94,6 @@ void ThreadHandler::check(const Settings &settings)
|
|||
|
||||
for (int i = 0; i < mRunningThreadCount; i++) {
|
||||
mThreads[i]->setAddonsAndTools(mAddonsAndTools);
|
||||
mThreads[i]->setMisraFile(mMisraFile);
|
||||
mThreads[i]->setSuppressions(mSuppressions);
|
||||
mThreads[i]->setClangIncludePaths(mClangIncludePaths);
|
||||
mThreads[i]->setDataDir(mDataDir);
|
||||
|
|
|
@ -72,9 +72,8 @@ public:
|
|||
*/
|
||||
void saveSettings(QSettings &settings) const;
|
||||
|
||||
void setAddonsAndTools(const QStringList &addonsAndTools, const QString &misraFile) {
|
||||
void setAddonsAndTools(const QStringList &addonsAndTools) {
|
||||
mAddonsAndTools = addonsAndTools;
|
||||
mMisraFile = misraFile;
|
||||
}
|
||||
|
||||
void setSuppressions(const QList<Suppressions::Suppression> &s) {
|
||||
|
@ -262,7 +261,6 @@ protected:
|
|||
QStringList mClangIncludePaths;
|
||||
|
||||
QString mDataDir;
|
||||
QString mMisraFile;
|
||||
private:
|
||||
|
||||
/**
|
||||
|
|
|
@ -87,7 +87,41 @@ namespace {
|
|||
return "";
|
||||
}
|
||||
|
||||
std::string parseAddonInfo(const picojson::value &json, const std::string &fileName, const std::string &exename) {
|
||||
std::string json_error = picojson::get_last_error();
|
||||
if (!json_error.empty()) {
|
||||
return "Loading " + fileName + " failed. " + json_error;
|
||||
}
|
||||
if (!json.is<picojson::object>())
|
||||
return "Loading " + fileName + " failed. Bad json.";
|
||||
picojson::object obj = json.get<picojson::object>();
|
||||
if (obj.count("args")) {
|
||||
if (!obj["args"].is<picojson::array>())
|
||||
return "Loading " + fileName + " failed. args must be array.";
|
||||
for (const picojson::value &v : obj["args"].get<picojson::array>())
|
||||
args += " " + v.get<std::string>();
|
||||
}
|
||||
|
||||
if (obj.count("python")) {
|
||||
// Python was defined in the config file
|
||||
if (obj["python"].is<picojson::array>()) {
|
||||
return "Loading " + fileName +" failed. python must not be an array.";
|
||||
}
|
||||
python = obj["python"].get<std::string>();
|
||||
} else {
|
||||
python = "";
|
||||
}
|
||||
|
||||
return getAddonInfo(obj["script"].get<std::string>(), exename);
|
||||
}
|
||||
|
||||
std::string getAddonInfo(const std::string &fileName, const std::string &exename) {
|
||||
if (fileName[0] == '{') {
|
||||
std::istringstream in(fileName);
|
||||
picojson::value json;
|
||||
in >> json;
|
||||
return parseAddonInfo(json, fileName, exename);
|
||||
}
|
||||
if (fileName.find(".") == std::string::npos)
|
||||
return getAddonInfo(fileName + ".py", exename);
|
||||
|
||||
|
@ -117,31 +151,7 @@ namespace {
|
|||
return "Failed to open " + fileName;
|
||||
picojson::value json;
|
||||
fin >> json;
|
||||
std::string json_error = picojson::get_last_error();
|
||||
if (!json_error.empty()) {
|
||||
return "Loading " + fileName + " failed. " + json_error;
|
||||
}
|
||||
if (!json.is<picojson::object>())
|
||||
return "Loading " + fileName + " failed. Bad json.";
|
||||
picojson::object obj = json.get<picojson::object>();
|
||||
if (obj.count("args")) {
|
||||
if (!obj["args"].is<picojson::array>())
|
||||
return "Loading " + fileName + " failed. args must be array.";
|
||||
for (const picojson::value &v : obj["args"].get<picojson::array>())
|
||||
args += " " + v.get<std::string>();
|
||||
}
|
||||
|
||||
if (obj.count("python")) {
|
||||
// Python was defined in the config file
|
||||
if (obj["python"].is<picojson::array>()) {
|
||||
return "Loading " + fileName +" failed. python must not be an array.";
|
||||
}
|
||||
python = obj["python"].get<std::string>();
|
||||
} else {
|
||||
python = "";
|
||||
}
|
||||
|
||||
return getAddonInfo(obj["script"].get<std::string>(), exename);
|
||||
return parseAddonInfo(json, fileName, exename);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ private:
|
|||
public:
|
||||
Settings();
|
||||
|
||||
/** @brief addons, either filename of python/json file or json data */
|
||||
std::list<std::string> addons;
|
||||
|
||||
/** @brief Path to the python interpreter to be used to run addons. */
|
||||
|
|
Loading…
Reference in New Issue