diff options
author | Ivan Donchevskii <ivan.donchevskii@qt.io> | 2018-07-10 15:53:51 +0200 |
---|---|---|
committer | Ivan Donchevskii <ivan.donchevskii@qt.io> | 2018-08-13 13:24:12 +0000 |
commit | f60b0352953b06d1a69e2b8b2ed117eab17135f9 (patch) | |
tree | 4d2a99c75a427d1e1a6d76cf1a16697f76ae35c8 | |
parent | 934e9b2e197199522d425af55b327108c255ae61 (diff) | |
download | qt-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.cpp | 99 | ||||
-rw-r--r-- | src/plugins/clangcodemodel/clangcodemodelplugin.h | 13 | ||||
-rw-r--r-- | src/plugins/clangcodemodel/clangconstants.h | 1 | ||||
-rw-r--r-- | src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp | 2 | ||||
-rw-r--r-- | src/plugins/clangcodemodel/clangutils.cpp | 55 | ||||
-rw-r--r-- | src/plugins/clangcodemodel/clangutils.h | 7 | ||||
-rw-r--r-- | src/plugins/cpptools/compileroptionsbuilder.cpp | 140 | ||||
-rw-r--r-- | src/plugins/cpptools/compileroptionsbuilder.h | 2 |
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 ¯os) 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() {} |