Clang: Add button to generate compile_commands.json

Change-Id: Iaabdcfc8d1b3463c3f6e5ce47536f9c52556eac0
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-07-10 15:53:51 +02:00
parent 934e9b2e19
commit f60b035295
8 changed files with 246 additions and 73 deletions

View File

@@ -27,27 +27,33 @@
#include "clangconstants.h" #include "clangconstants.h"
#include "clangprojectsettingswidget.h" #include "clangprojectsettingswidget.h"
#include "clangutils.h"
#ifdef WITH_TESTS #ifdef WITH_TESTS
# include "test/clangbatchfileprocessor.h" # include "test/clangbatchfileprocessor.h"
# include "test/clangcodecompletion_test.h" # include "test/clangcodecompletion_test.h"
#endif #endif
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <cpptools/cppmodelmanager.h> #include <cpptools/cppmodelmanager.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/projectpanelfactory.h> #include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h> #include <projectexplorer/taskhub.h>
#include <texteditor/textmark.h> #include <texteditor/textmark.h>
#include <QtConcurrent>
namespace ClangCodeModel { namespace ClangCodeModel {
namespace Internal { namespace Internal {
namespace { static void addProjectPanelWidget()
void addProjectPanelWidget()
{ {
auto panelFactory = new ProjectExplorer::ProjectPanelFactory(); auto panelFactory = new ProjectExplorer::ProjectPanelFactory();
panelFactory->setPriority(60); panelFactory->setPriority(60);
@@ -58,7 +64,32 @@ void addProjectPanelWidget()
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
} }
} // anonymous namespace void ClangCodeModelPlugin::generateCompilationDB() {
using namespace CppTools;
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
if (!project)
return;
m_generatorWatcher.setFuture(QtConcurrent::run(
&Utils::generateCompilationDB,
project->projectDirectory(),
CppModelManager::instance()->projectInfo(project)));
}
static bool isDBGenerationEnabled(ProjectExplorer::Project *project)
{
using namespace CppTools;
if (!project)
return false;
ProjectInfo projectInfo = CppModelManager::instance()->projectInfo(project);
return projectInfo.isValid() && !projectInfo.projectParts().isEmpty();
}
ClangCodeModelPlugin::~ClangCodeModelPlugin()
{
m_generatorWatcher.waitForFinished();
}
bool ClangCodeModelPlugin::initialize(const QStringList &arguments, QString *errorMessage) bool ClangCodeModelPlugin::initialize(const QStringList &arguments, QString *errorMessage)
{ {
@@ -77,9 +108,69 @@ bool ClangCodeModelPlugin::initialize(const QStringList &arguments, QString *err
addProjectPanelWidget(); addProjectPanelWidget();
createCompilationDBButton();
return true; return true;
} }
void ClangCodeModelPlugin::createCompilationDBButton()
{
Core::ActionContainer *mbuild =
Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT);
// generate compile_commands.json
m_generateCompilationDBAction = new ::Utils::ParameterAction(
tr("Generate compilation database"),
tr("Generate compilation database for \"%1\""),
::Utils::ParameterAction::AlwaysEnabled, this);
ProjectExplorer::Project *startupProject = ProjectExplorer::SessionManager::startupProject();
m_generateCompilationDBAction->setEnabled(isDBGenerationEnabled(startupProject));
if (startupProject)
m_generateCompilationDBAction->setParameter(startupProject->displayName());
Core::Command *command = Core::ActionManager::registerAction(m_generateCompilationDBAction,
Constants::GENERATE_COMPILATION_DB);
command->setAttribute(Core::Command::CA_UpdateText);
command->setDescription(m_generateCompilationDBAction->text());
mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD);
connect(&m_generatorWatcher, &QFutureWatcher<void>::finished, this, [this] () {
m_generateCompilationDBAction->setEnabled(
isDBGenerationEnabled(ProjectExplorer::SessionManager::startupProject()));
});
connect(m_generateCompilationDBAction, &QAction::triggered, this, [this] {
if (!m_generateCompilationDBAction->isEnabled())
return;
m_generateCompilationDBAction->setEnabled(false);
generateCompilationDB();
});
connect(CppTools::CppModelManager::instance(), &CppTools::CppModelManager::projectPartsUpdated,
this, [this](ProjectExplorer::Project *project) {
if (project != ProjectExplorer::SessionManager::startupProject())
return;
m_generateCompilationDBAction->setParameter(project->displayName());
if (!m_generatorWatcher.isRunning())
m_generateCompilationDBAction->setEnabled(isDBGenerationEnabled(project));
});
connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::startupProjectChanged,
this,
[this](ProjectExplorer::Project *project) {
m_generateCompilationDBAction->setParameter(project->displayName());
if (!m_generatorWatcher.isRunning())
m_generateCompilationDBAction->setEnabled(isDBGenerationEnabled(project));
});
connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::projectDisplayNameChanged,
this,
[this](ProjectExplorer::Project *project) {
if (project != ProjectExplorer::SessionManager::startupProject())
return;
m_generateCompilationDBAction->setParameter(project->displayName());
});
}
void ClangCodeModelPlugin::extensionsInitialized() void ClangCodeModelPlugin::extensionsInitialized()
{ {
} }

View File

@@ -29,15 +29,20 @@
#include <extensionsystem/iplugin.h> #include <extensionsystem/iplugin.h>
#include <utils/parameteraction.h>
#include <QFutureWatcher>
namespace ClangCodeModel { namespace ClangCodeModel {
namespace Internal { namespace Internal {
class ClangCodeModelPlugin: public ExtensionSystem::IPlugin class ClangCodeModelPlugin final: public ExtensionSystem::IPlugin
{ {
Q_OBJECT Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangCodeModel.json") Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangCodeModel.json")
public: public:
~ClangCodeModelPlugin();
bool initialize(const QStringList &arguments, QString *errorMessage); bool initialize(const QStringList &arguments, QString *errorMessage);
void extensionsInitialized(); void extensionsInitialized();
@@ -45,8 +50,12 @@ private:
void maybeHandleBatchFileAndExit() const; void maybeHandleBatchFileAndExit() const;
private: private:
ModelManagerSupportProviderClang m_modelManagerSupportProvider; void generateCompilationDB();
void createCompilationDBButton();
ModelManagerSupportProviderClang m_modelManagerSupportProvider;
Utils::ParameterAction *m_generateCompilationDBAction = nullptr;
QFutureWatcher<void> m_generatorWatcher;
#ifdef WITH_TESTS #ifdef WITH_TESTS
QList<QObject *> createTestObjects() const; QList<QObject *> createTestObjects() const;
#endif #endif

View File

@@ -29,6 +29,7 @@ namespace ClangCodeModel {
namespace Constants { namespace Constants {
const char CLANG_MODELMANAGERSUPPORT_ID[] = "ClangCodeModel.ClangCodeModel"; const char CLANG_MODELMANAGERSUPPORT_ID[] = "ClangCodeModel.ClangCodeModel";
const char GENERATE_COMPILATION_DB[] = "ClangCodeModel.GenerateCompilationDB";
const char CLANG_ERROR[] = "Clang.Error"; const char CLANG_ERROR[] = "Clang.Error";
const char CLANG_WARNING[] = "Clang.Warning"; const char CLANG_WARNING[] = "Clang.Warning";

View File

@@ -475,7 +475,7 @@ private:
} }
CppTools::CompilerOptionsBuilder builder(m_projectPart); CppTools::CompilerOptionsBuilder builder(m_projectPart);
builder.addLanguageOption(fileKind); builder.updateLanguageOption(fileKind);
m_options.append(builder.options()); m_options.append(builder.options());
} }

View File

@@ -39,13 +39,19 @@
#include <cpptools/projectpart.h> #include <cpptools/projectpart.h>
#include <cpptools/cppcodemodelsettings.h> #include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cpptoolsreuse.h> #include <cpptools/cpptoolsreuse.h>
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStringList> #include <QStringList>
#include <QTextBlock> #include <QTextBlock>
@@ -357,5 +363,54 @@ QString diagnosticCategoryPrefixRemoved(const QString &text)
return text; return text;
} }
static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart)
{
ProjectExplorer::Target *target = projectPart.project->activeTarget();
if (!target)
return ::Utils::FileName();
ProjectExplorer::BuildConfiguration *buildConfig = target->activeBuildConfiguration();
if (!buildConfig)
return ::Utils::FileName();
return buildConfig->buildDirectory();
}
static QJsonObject createFileObject(CompilerOptionsBuilder &optionsBuilder,
const ProjectFile &projFile,
const ::Utils::FileName &buildDir)
{
optionsBuilder.updateLanguageOption(ProjectFile::classify(projFile.path));
QJsonObject fileObject;
fileObject["file"] = projFile.path;
QJsonArray args = QJsonArray::fromStringList(optionsBuilder.options());
args.append(QDir::toNativeSeparators(projFile.path));
fileObject["arguments"] = args;
fileObject["directory"] = buildDir.toString();
return fileObject;
}
void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo)
{
QFile compileCommandsFile(projectDir.toString() + "/compile_commands.json");
QJsonArray array;
for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) {
const ::Utils::FileName buildDir = buildDirectory(*projectPart);
CompilerOptionsBuilder optionsBuilder(*projectPart);
optionsBuilder.build(CppTools::ProjectFile::Unclassified,
CppTools::CompilerOptionsBuilder::PchUsage::None);
for (const ProjectFile &projFile : projectPart->files)
array.push_back(createFileObject(optionsBuilder, projFile, buildDir));
}
compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
compileCommandsFile.write(QJsonDocument(array).toJson());
compileCommandsFile.close();
}
} // namespace Utils } // namespace Utils
} // namespace Clang } // namespace Clang

View File

@@ -35,6 +35,11 @@ QT_END_NAMESPACE
namespace CppTools { namespace CppTools {
class CppEditorDocumentHandle; class CppEditorDocumentHandle;
class ProjectInfo;
}
namespace Utils {
class FileName;
} }
namespace ClangBackEnd { class TokenInfoContainer; } namespace ClangBackEnd { class TokenInfoContainer; }
@@ -60,5 +65,7 @@ QString diagnosticCategoryPrefixRemoved(const QString &text);
::Utils::CodeModelIcon::Type iconTypeForToken(const ClangBackEnd::TokenInfoContainer &token); ::Utils::CodeModelIcon::Type iconTypeForToken(const ClangBackEnd::TokenInfoContainer &token);
void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo);
} // namespace Utils } // namespace Utils
} // namespace Clang } // namespace Clang

View File

@@ -28,7 +28,6 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/vcsmanager.h> #include <coreplugin/vcsmanager.h>
#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
@@ -53,10 +52,12 @@ QStringList CompilerOptionsBuilder::build(CppTools::ProjectFile::Kind fileKind,
return QStringList();); return QStringList(););
} }
add("-c");
addWordWidth(); addWordWidth();
addTargetTriple(); addTargetTriple();
addExtraCodeModelFlags(); addExtraCodeModelFlags();
addLanguageOption(fileKind); updateLanguageOption(fileKind);
addOptionsForLanguage(/*checkForBorlandExtensions*/ true); addOptionsForLanguage(/*checkForBorlandExtensions*/ true);
enableExceptions(); enableExceptions();
@@ -77,6 +78,67 @@ QStringList CompilerOptionsBuilder::build(CppTools::ProjectFile::Kind fileKind,
return options(); return options();
} }
static QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt)
{
QStringList opts;
switch (fileKind) {
case ProjectFile::Unclassified:
case ProjectFile::Unsupported:
break;
case ProjectFile::CHeader:
if (objcExt)
opts += QLatin1String("objective-c-header");
else
opts += QLatin1String("c-header");
break;
case ProjectFile::CXXHeader:
default:
if (!objcExt) {
opts += QLatin1String("c++-header");
break;
}
Q_FALLTHROUGH();
case ProjectFile::ObjCHeader:
case ProjectFile::ObjCXXHeader:
opts += QLatin1String("objective-c++-header");
break;
case ProjectFile::CSource:
if (!objcExt) {
opts += QLatin1String("c");
break;
}
Q_FALLTHROUGH();
case ProjectFile::ObjCSource:
opts += QLatin1String("objective-c");
break;
case ProjectFile::CXXSource:
if (!objcExt) {
opts += QLatin1String("c++");
break;
}
Q_FALLTHROUGH();
case ProjectFile::ObjCXXSource:
opts += QLatin1String("objective-c++");
break;
case ProjectFile::OpenCLSource:
opts += QLatin1String("cl");
break;
case ProjectFile::CudaSource:
opts += QLatin1String("cuda");
break;
}
if (!opts.isEmpty())
opts.prepend(QLatin1String("-x"));
return opts;
}
QStringList CompilerOptionsBuilder::options() const QStringList CompilerOptionsBuilder::options() const
{ {
return m_options; return m_options;
@@ -197,72 +259,20 @@ void CompilerOptionsBuilder::addMacros(const ProjectExplorer::Macros &macros)
m_options.append(result); m_options.append(result);
} }
static QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt) void CompilerOptionsBuilder::updateLanguageOption(ProjectFile::Kind fileKind)
{
QStringList opts;
switch (fileKind) {
case ProjectFile::Unclassified:
case ProjectFile::Unsupported:
break;
case ProjectFile::CHeader:
if (objcExt)
opts += QLatin1String("objective-c-header");
else
opts += QLatin1String("c-header");
break;
case ProjectFile::CXXHeader:
default:
if (!objcExt) {
opts += QLatin1String("c++-header");
break;
}
Q_FALLTHROUGH();
case ProjectFile::ObjCHeader:
case ProjectFile::ObjCXXHeader:
opts += QLatin1String("objective-c++-header");
break;
case ProjectFile::CSource:
if (!objcExt) {
opts += QLatin1String("c");
break;
}
Q_FALLTHROUGH();
case ProjectFile::ObjCSource:
opts += QLatin1String("objective-c");
break;
case ProjectFile::CXXSource:
if (!objcExt) {
opts += QLatin1String("c++");
break;
}
Q_FALLTHROUGH();
case ProjectFile::ObjCXXSource:
opts += QLatin1String("objective-c++");
break;
case ProjectFile::OpenCLSource:
opts += QLatin1String("cl");
break;
case ProjectFile::CudaSource:
opts += QLatin1String("cuda");
break;
}
if (!opts.isEmpty())
opts.prepend(QLatin1String("-x"));
return opts;
}
void CompilerOptionsBuilder::addLanguageOption(ProjectFile::Kind fileKind)
{ {
const bool objcExt = m_projectPart.languageExtensions & ProjectPart::ObjectiveCExtensions; const bool objcExt = m_projectPart.languageExtensions & ProjectPart::ObjectiveCExtensions;
const QStringList options = createLanguageOptionGcc(fileKind, objcExt); const QStringList options = createLanguageOptionGcc(fileKind, objcExt);
if (options.isEmpty())
return;
QTC_ASSERT(options.size() == 2, return;);
int langOptIndex = m_options.indexOf("-x");
if (langOptIndex == -1) {
m_options.append(options); m_options.append(options);
} else {
m_options[langOptIndex + 1] = options[1];
}
} }
void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtensions) void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtensions)

View File

@@ -46,8 +46,8 @@ public:
virtual void addExtraCodeModelFlags(); virtual void addExtraCodeModelFlags();
virtual void enableExceptions(); virtual void enableExceptions();
virtual void addPredefinedHeaderPathsOptions(); virtual void addPredefinedHeaderPathsOptions();
virtual void addLanguageOption(ProjectFile::Kind fileKind);
virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true); virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true);
virtual void updateLanguageOption(ProjectFile::Kind fileKind);
virtual void addExtraOptions() {} virtual void addExtraOptions() {}