Files
qt-creator/src/plugins/clangtools/executableinfo.cpp
Christian Kandeler 078ca0cdff ClangTools: Work around clazy-standalone behavior fluctuation
Some versions expect an argument after the -supported-checks-json
option, and some don't. They are not easily identifiable, so we try both
versions of the command line.

Change-Id: I5b265e4ddd4a21c238228dafc60cbc09194f23cc
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
2020-05-27 13:26:03 +00:00

167 lines
5.5 KiB
C++

/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "executableinfo.h"
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <utils/environment.h>
#include <utils/synchronousprocess.h>
#include <QFileInfo>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTextStream>
using namespace Utils;
namespace ClangTools {
namespace Internal {
static QString runExecutable(const Utils::CommandLine &commandLine)
{
if (commandLine.executable().isEmpty() || !commandLine.executable().toFileInfo().isExecutable())
return {};
SynchronousProcess cpp;
Utils::Environment env = Environment::systemEnvironment();
Environment::setupEnglishOutput(&env);
cpp.setEnvironment(env.toStringList());
SynchronousProcessResponse response = cpp.runBlocking(commandLine);
if (response.result != SynchronousProcessResponse::Finished || response.exitCode != 0) {
Core::MessageManager::write(response.exitMessage(commandLine.toUserOutput(), 10));
Core::MessageManager::write(QString::fromUtf8(response.allRawOutput()));
return {};
}
return response.allOutput();
}
static QStringList queryClangTidyChecks(const QString &executable,
const QString &checksArgument)
{
QStringList arguments = QStringList("-list-checks");
if (!checksArgument.isEmpty())
arguments.prepend(checksArgument);
const CommandLine commandLine(executable, arguments);
QString output = runExecutable(commandLine);
if (output.isEmpty())
return {};
// Expected output is (clang-tidy 8.0):
// Enabled checks:
// abseil-duration-comparison
// abseil-duration-division
// abseil-duration-factory-float
// ...
QTextStream stream(&output);
QString line = stream.readLine();
if (!line.startsWith("Enabled checks:"))
return {};
QStringList checks;
while (!stream.atEnd()) {
const QString candidate = stream.readLine().trimmed();
if (!candidate.isEmpty())
checks << candidate;
}
return checks;
}
static ClazyChecks querySupportedClazyChecks(const QString &executablePath)
{
static const QString queryFlag = "-supported-checks-json";
QString jsonOutput = runExecutable(CommandLine(executablePath, {queryFlag}));
// Some clazy 1.6.x versions have a bug where they expect an argument after the
// option.
if (jsonOutput.isEmpty())
jsonOutput = runExecutable(CommandLine(executablePath, {queryFlag, "dummy"}));
if (jsonOutput.isEmpty())
return {};
// Expected output is (clazy-standalone 1.6):
// {
// "available_categories" : ["readability", "qt4", "containers", ... ],
// "checks" : [
// {
// "name" : "qt-keywords",
// "level" : -1,
// "fixits" : [ { "name" : "qt-keywords" } ]
// },
// ...
// {
// "name" : "inefficient-qlist",
// "level" : -1,
// "categories" : ["containers", "performance"],
// "visits_decls" : true
// },
// ...
// ]
// }
ClazyChecks infos;
const QJsonDocument document = QJsonDocument::fromJson(jsonOutput.toUtf8());
if (document.isNull())
return {};
const QJsonArray checksArray = document.object()["checks"].toArray();
for (const QJsonValue &item: checksArray) {
const QJsonObject checkObject = item.toObject();
ClazyCheck info;
info.name = checkObject["name"].toString().trimmed();
if (info.name.isEmpty())
continue;
info.level = checkObject["level"].toInt();
for (const QJsonValue &item : checkObject["categories"].toArray())
info.topics.append(item.toString().trimmed());
infos << info;
}
return infos;
}
ClangTidyInfo::ClangTidyInfo(const QString &executablePath)
: defaultChecks(queryClangTidyChecks(executablePath, {}))
, supportedChecks(queryClangTidyChecks(executablePath, "-checks=*"))
{}
ClazyStandaloneInfo::ClazyStandaloneInfo(const QString &executablePath)
: defaultChecks(queryClangTidyChecks(executablePath, {})) // Yup, behaves as clang-tidy.
, supportedChecks(querySupportedClazyChecks(executablePath))
{}
} // namespace Internal
} // namespace ClangTools