summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Donchevskii <ivan.donchevskii@qt.io>2018-07-10 15:53:51 +0200
committerIvan Donchevskii <ivan.donchevskii@qt.io>2018-08-13 13:24:12 +0000
commitf60b0352953b06d1a69e2b8b2ed117eab17135f9 (patch)
tree4d2a99c75a427d1e1a6d76cf1a16697f76ae35c8
parent934e9b2e197199522d425af55b327108c255ae61 (diff)
downloadqt-creator-f60b0352953b06d1a69e2b8b2ed117eab17135f9.tar.gz
Clang: Add button to generate compile_commands.json
Change-Id: Iaabdcfc8d1b3463c3f6e5ce47536f9c52556eac0 Reviewed-by: Marco Bubke <marco.bubke@qt.io>
-rw-r--r--src/plugins/clangcodemodel/clangcodemodelplugin.cpp99
-rw-r--r--src/plugins/clangcodemodel/clangcodemodelplugin.h13
-rw-r--r--src/plugins/clangcodemodel/clangconstants.h1
-rw-r--r--src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp2
-rw-r--r--src/plugins/clangcodemodel/clangutils.cpp55
-rw-r--r--src/plugins/clangcodemodel/clangutils.h7
-rw-r--r--src/plugins/cpptools/compileroptionsbuilder.cpp140
-rw-r--r--src/plugins/cpptools/compileroptionsbuilder.h2
8 files changed, 246 insertions, 73 deletions
diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
index b2c44f0e90..faec14f783 100644
--- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
+++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
@@ -27,27 +27,33 @@
#include "clangconstants.h"
#include "clangprojectsettingswidget.h"
+#include "clangutils.h"
#ifdef WITH_TESTS
# include "test/clangbatchfileprocessor.h"
# include "test/clangcodecompletion_test.h"
#endif
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+
#include <cpptools/cppmodelmanager.h>
+#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/projectpanelfactory.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
+#include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h>
#include <texteditor/textmark.h>
+#include <QtConcurrent>
+
namespace ClangCodeModel {
namespace Internal {
-namespace {
-
-void addProjectPanelWidget()
+static void addProjectPanelWidget()
{
auto panelFactory = new ProjectExplorer::ProjectPanelFactory();
panelFactory->setPriority(60);
@@ -58,7 +64,32 @@ void addProjectPanelWidget()
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)
{
@@ -77,9 +108,69 @@ bool ClangCodeModelPlugin::initialize(const QStringList &arguments, QString *err
addProjectPanelWidget();
+ createCompilationDBButton();
+
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()
{
}
diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.h b/src/plugins/clangcodemodel/clangcodemodelplugin.h
index 8e41fe6020..5e24352a76 100644
--- a/src/plugins/clangcodemodel/clangcodemodelplugin.h
+++ b/src/plugins/clangcodemodel/clangcodemodelplugin.h
@@ -29,15 +29,20 @@
#include <extensionsystem/iplugin.h>
+#include <utils/parameteraction.h>
+
+#include <QFutureWatcher>
+
namespace ClangCodeModel {
namespace Internal {
-class ClangCodeModelPlugin: public ExtensionSystem::IPlugin
+class ClangCodeModelPlugin final: public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangCodeModel.json")
public:
+ ~ClangCodeModelPlugin();
bool initialize(const QStringList &arguments, QString *errorMessage);
void extensionsInitialized();
@@ -45,8 +50,12 @@ private:
void maybeHandleBatchFileAndExit() const;
private:
- ModelManagerSupportProviderClang m_modelManagerSupportProvider;
+ void generateCompilationDB();
+ void createCompilationDBButton();
+ ModelManagerSupportProviderClang m_modelManagerSupportProvider;
+ Utils::ParameterAction *m_generateCompilationDBAction = nullptr;
+ QFutureWatcher<void> m_generatorWatcher;
#ifdef WITH_TESTS
QList<QObject *> createTestObjects() const;
#endif
diff --git a/src/plugins/clangcodemodel/clangconstants.h b/src/plugins/clangcodemodel/clangconstants.h
index 294618aa88..da6223f133 100644
--- a/src/plugins/clangcodemodel/clangconstants.h
+++ b/src/plugins/clangcodemodel/clangconstants.h
@@ -29,6 +29,7 @@ namespace ClangCodeModel {
namespace Constants {
const char CLANG_MODELMANAGERSUPPORT_ID[] = "ClangCodeModel.ClangCodeModel";
+const char GENERATE_COMPILATION_DB[] = "ClangCodeModel.GenerateCompilationDB";
const char CLANG_ERROR[] = "Clang.Error";
const char CLANG_WARNING[] = "Clang.Warning";
diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
index 2c6608c6b8..25054f14ec 100644
--- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
+++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
@@ -475,7 +475,7 @@ private:
}
CppTools::CompilerOptionsBuilder builder(m_projectPart);
- builder.addLanguageOption(fileKind);
+ builder.updateLanguageOption(fileKind);
m_options.append(builder.options());
}
diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp
index 8bd698c2d1..b58304eb2b 100644
--- a/src/plugins/clangcodemodel/clangutils.cpp
+++ b/src/plugins/clangcodemodel/clangutils.cpp
@@ -39,13 +39,19 @@
#include <cpptools/projectpart.h>
#include <cpptools/cppcodemodelsettings.h>
#include <cpptools/cpptoolsreuse.h>
+#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/target.h>
#include <utils/algorithm.h>
+#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <QDir>
#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
#include <QStringList>
#include <QTextBlock>
@@ -357,5 +363,54 @@ QString diagnosticCategoryPrefixRemoved(const QString &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 Clang
diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h
index c9637544f0..d35aaf1f26 100644
--- a/src/plugins/clangcodemodel/clangutils.h
+++ b/src/plugins/clangcodemodel/clangutils.h
@@ -35,6 +35,11 @@ QT_END_NAMESPACE
namespace CppTools {
class CppEditorDocumentHandle;
+class ProjectInfo;
+}
+
+namespace Utils {
+class FileName;
}
namespace ClangBackEnd { class TokenInfoContainer; }
@@ -60,5 +65,7 @@ QString diagnosticCategoryPrefixRemoved(const QString &text);
::Utils::CodeModelIcon::Type iconTypeForToken(const ClangBackEnd::TokenInfoContainer &token);
+void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo);
+
} // namespace Utils
} // namespace Clang
diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp
index 5e5721dc7c..041cbf607b 100644
--- a/src/plugins/cpptools/compileroptionsbuilder.cpp
+++ b/src/plugins/cpptools/compileroptionsbuilder.cpp
@@ -28,7 +28,6 @@
#include <coreplugin/icore.h>
#include <coreplugin/vcsmanager.h>
-#include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <utils/fileutils.h>
@@ -53,10 +52,12 @@ QStringList CompilerOptionsBuilder::build(CppTools::ProjectFile::Kind fileKind,
return QStringList(););
}
+ add("-c");
+
addWordWidth();
addTargetTriple();
addExtraCodeModelFlags();
- addLanguageOption(fileKind);
+ updateLanguageOption(fileKind);
addOptionsForLanguage(/*checkForBorlandExtensions*/ true);
enableExceptions();
@@ -77,6 +78,67 @@ QStringList CompilerOptionsBuilder::build(CppTools::ProjectFile::Kind fileKind,
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
{
return m_options;
@@ -197,72 +259,20 @@ void CompilerOptionsBuilder::addMacros(const ProjectExplorer::Macros &macros)
m_options.append(result);
}
-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;
-}
-
-void CompilerOptionsBuilder::addLanguageOption(ProjectFile::Kind fileKind)
+void CompilerOptionsBuilder::updateLanguageOption(ProjectFile::Kind fileKind)
{
const bool objcExt = m_projectPart.languageExtensions & ProjectPart::ObjectiveCExtensions;
const QStringList options = createLanguageOptionGcc(fileKind, objcExt);
- m_options.append(options);
+ if (options.isEmpty())
+ return;
+
+ QTC_ASSERT(options.size() == 2, return;);
+ int langOptIndex = m_options.indexOf("-x");
+ if (langOptIndex == -1) {
+ m_options.append(options);
+ } else {
+ m_options[langOptIndex + 1] = options[1];
+ }
}
void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtensions)
diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h
index 33a72820e4..eddbd6d3fb 100644
--- a/src/plugins/cpptools/compileroptionsbuilder.h
+++ b/src/plugins/cpptools/compileroptionsbuilder.h
@@ -46,8 +46,8 @@ public:
virtual void addExtraCodeModelFlags();
virtual void enableExceptions();
virtual void addPredefinedHeaderPathsOptions();
- virtual void addLanguageOption(ProjectFile::Kind fileKind);
virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true);
+ virtual void updateLanguageOption(ProjectFile::Kind fileKind);
virtual void addExtraOptions() {}