diff options
Diffstat (limited to 'src/plugins/clangstaticanalyzer')
6 files changed, 156 insertions, 4 deletions
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp index f65a8a6931..dd3e59d2c4 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp @@ -47,7 +47,7 @@ ClangStaticAnalyzerConfigWidget::ClangStaticAnalyzerConfigWidget( chooser->setExpectedKind(Utils::PathChooser::ExistingCommand); chooser->setHistoryCompleter(QLatin1String("ClangStaticAnalyzer.ClangCommand.History")); chooser->setPromptDialogTitle(tr("Clang Command")); - const auto validator = [chooser](Utils::FancyLineEdit *edit, QString *errorMessage) { + const auto validator = [chooser, this](Utils::FancyLineEdit *edit, QString *errorMessage) { const QString currentFilePath = chooser->fileName().toString(); Utils::PathChooser pc; Utils::PathChooser *helperPathChooser; @@ -58,8 +58,17 @@ ClangStaticAnalyzerConfigWidget::ClangStaticAnalyzerConfigWidget( } else { helperPathChooser = chooser; } - return chooser->defaultValidationFunction()(helperPathChooser->lineEdit(), errorMessage) + + const bool isExecutableValid = + chooser->defaultValidationFunction()(helperPathChooser->lineEdit(), errorMessage) && isClangExecutableUsable(helperPathChooser->fileName().toString(), errorMessage); + + const ClangExecutableVersion detectedVersion = isExecutableValid + ? clangExecutableVersion(helperPathChooser->fileName().toString()) + : ClangExecutableVersion(); + updateDetectedVersionLabel(isExecutableValid, detectedVersion); + + return isExecutableValid; }; chooser->setValidationFunction(validator); bool clangExeIsSet; @@ -90,5 +99,29 @@ ClangStaticAnalyzerConfigWidget::~ClangStaticAnalyzerConfigWidget() delete m_ui; } +void ClangStaticAnalyzerConfigWidget::updateDetectedVersionLabel( + bool isExecutableValid, + const ClangExecutableVersion &providedVersion) +{ + QLabel &label = *m_ui->detectedVersionLabel; + + if (isExecutableValid) { + if (providedVersion.isValid()) { + if (providedVersion.isSupportedVersion()) { + label.setText(tr("Version: %1, supported.") + .arg(providedVersion.toString())); + } else { + label.setText(tr("Version: %1, unsupported (supported version is %2).") + .arg(providedVersion.toString()) + .arg(ClangExecutableVersion::supportedVersionAsString())); + } + } else { + label.setText(tr("Version: Could not determine version.")); + } + } else { + label.setText(tr("Version: Set valid executable first.")); + } +} + } // namespace Internal } // namespace ClangStaticAnalyzer diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.h index f410670e50..6cc4e39eaf 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.h @@ -34,6 +34,8 @@ namespace Internal { namespace Ui { class ClangStaticAnalyzerConfigWidget; } +class ClangExecutableVersion; + class ClangStaticAnalyzerConfigWidget : public QWidget { Q_OBJECT @@ -43,6 +45,9 @@ public: QWidget *parent = 0); ~ClangStaticAnalyzerConfigWidget(); + void updateDetectedVersionLabel(bool executableIsValid, + const ClangExecutableVersion &providedVersion); + private: Ui::ClangStaticAnalyzerConfigWidget *m_ui; ClangStaticAnalyzerSettings *m_settings; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui index 800733a331..3f4d3762ec 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui @@ -34,14 +34,21 @@ </item> </layout> </item> - <item row="1" column="0"> + <item row="1" column="1"> + <widget class="QLabel" name="detectedVersionLabel"> + <property name="text"> + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="2" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Simultaneous processes:</string> </property> </widget> </item> - <item row="1" column="1"> + <item row="2" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QSpinBox" name="simultaneousProccessesSpinBox"> diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 1fa42fa11b..f140907a66 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -469,6 +469,28 @@ void ClangStaticAnalyzerRunControl::start() emit finished(); return; } + + // Check clang version + const ClangExecutableVersion version = clangExecutableVersion(executable); + if (!version.isValid()) { + const QString warningMessage + = tr("Clang Static Analyzer: Running with possibly unsupported version, " + "could not determine version from executable \"%1\".") + .arg(executable); + appendMessage(warningMessage + QLatin1Char('\n'), Utils::StdErrFormat); + TaskHub::addTask(Task::Warning, warningMessage, Debugger::Constants::ANALYZERTASK_ID); + TaskHub::requestPopup(); + } else if (!version.isSupportedVersion()) { + const QString warningMessage + = tr("Clang Static Analyzer: Running with unsupported version %1, " + "supported version is %2.") + .arg(version.toString()) + .arg(ClangExecutableVersion::supportedVersionAsString()); + appendMessage(warningMessage + QLatin1Char('\n'), Utils::StdErrFormat); + TaskHub::addTask(Task::Warning, warningMessage, Debugger::Constants::ANALYZERTASK_ID); + TaskHub::requestPopup(); + } + m_clangExecutable = executable; // Create log dir diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp index 0b7bc0f230..a1a1bee67a 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp @@ -32,9 +32,11 @@ #include <utils/hostosinfo.h> #include <utils/environment.h> +#include <utils/synchronousprocess.h> #include <QCoreApplication> #include <QFileInfo> +#include <QRegularExpression> static bool isFileExecutable(const QString &executablePath) { @@ -108,5 +110,53 @@ bool isClangExecutableUsable(const QString &filePath, QString *errorMessage) return true; } +ClangExecutableVersion clangExecutableVersion(const QString &executable) +{ + const ClangExecutableVersion invalidVersion; + + // Sanity checks + const QFileInfo fileInfo(executable); + const bool isExecutableFile = fileInfo.isFile() && fileInfo.isExecutable(); + if (!isExecutableFile) + return invalidVersion; + + // Get version output + Utils::Environment environment = Utils::Environment::systemEnvironment(); + Utils::Environment::setupEnglishOutput(&environment); + Utils::SynchronousProcess runner; + runner.setEnvironment(environment.toStringList()); + runner.setTimeoutS(10); + // We would prefer "-dumpversion", but that one returns some old version number. + const QStringList arguments(QLatin1String(("--version"))); + const Utils::SynchronousProcessResponse response = runner.runBlocking(executable, arguments); + if (response.result != Utils::SynchronousProcessResponse::Finished) + return invalidVersion; + const QString output = response.stdOut(); + + // Parse version output + const QRegularExpression re(QLatin1String("clang version (\\d+)\\.(\\d+)\\.(\\d+)")); + const QRegularExpressionMatch reMatch = re.match(output); + if (re.captureCount() != 3) + return invalidVersion; + + const QString majorString = reMatch.captured(1); + bool convertedSuccessfully = false; + const int major = majorString.toInt(&convertedSuccessfully); + if (!convertedSuccessfully) + return invalidVersion; + + const QString minorString = reMatch.captured(2); + const int minor = minorString.toInt(&convertedSuccessfully); + if (!convertedSuccessfully) + return invalidVersion; + + const QString patchString = reMatch.captured(3); + const int patch = patchString.toInt(&convertedSuccessfully); + if (!convertedSuccessfully) + return invalidVersion; + + return ClangExecutableVersion(major, minor, patch); +} + } // namespace Internal } // namespace ClangStaticAnalyzer diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h index 6b0880fc67..fb86bc1f94 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h @@ -44,5 +44,40 @@ QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid); QString createFullLocationString(const Debugger::DiagnosticLocation &location); +// TODO: Use QVersionNumber once we can use >= Qt 5.6.0 +class ClangExecutableVersion { +public: + ClangExecutableVersion() : majorNumber(-1) , minorNumber(-1) , patchNumber(-1) {} + ClangExecutableVersion(int major, int minor, int patch) + : majorNumber(major) , minorNumber(minor) , patchNumber(patch) {} + + bool isValid() const + { + return majorNumber >= 0 && minorNumber >= 0 && patchNumber >= 0; + } + + bool isSupportedVersion() const + { + return majorNumber == 3 && minorNumber == 8; + } + + static QString supportedVersionAsString() + { + return QLatin1String("3.8"); + } + + QString toString() const + { + return QString::fromLatin1("%1.%2.%3").arg(majorNumber).arg(minorNumber).arg(patchNumber); + } + +public: + int majorNumber; + int minorNumber; + int patchNumber; +}; + +ClangExecutableVersion clangExecutableVersion(const QString &absolutePath); + } // namespace Internal } // namespace ClangStaticAnalyzer |