// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "clangcodemodeltr.h" #include "clangconstants.h" #include "clangmodelmanagersupport.h" #include "clangutils.h" #ifdef WITH_TESTS # include "test/activationsequenceprocessortest.h" # include "test/clangdtests.h" # include "test/clangfixittest.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Core; using namespace ProjectExplorer; using namespace Utils; namespace ClangCodeModel::Internal { class ClangCodeModelPlugin final: public ExtensionSystem::IPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangCodeModel.json") public: ~ClangCodeModelPlugin() final; void initialize() final; private: void generateCompilationDB(); void createCompilationDBAction(); Utils::Action *m_generateCompilationDBAction = nullptr; QFutureWatcher m_generatorWatcher; }; ClangCodeModelPlugin::~ClangCodeModelPlugin() { m_generatorWatcher.waitForFinished(); } void ClangCodeModelPlugin::initialize() { TaskHub::addCategory({Constants::TASK_CATEGORY_DIAGNOSTICS, Tr::tr("Clang Code Model"), Tr::tr("C++ code issues that Clangd found in the current document.")}); CppEditor::CppModelManager::activateClangCodeModel(std::make_unique()); createCompilationDBAction(); ActionBuilder updateStaleIndexEntries(this, "ClangCodeModel.UpdateStaleIndexEntries"); updateStaleIndexEntries.setText(Tr::tr("Update Potentially Stale Clangd Index Entries")); updateStaleIndexEntries.addOnTriggered(this, &ClangModelManagerSupport::updateStaleIndexEntries); updateStaleIndexEntries.addToContainer(CppEditor::Constants::M_TOOLS_CPP); updateStaleIndexEntries.addToContainer(CppEditor::Constants::M_CONTEXT); #ifdef WITH_TESTS addTestCreator(createActivationSequenceProcessorTest); addTestCreator(createClangdTestCompletion); addTestCreator(createClangdTestExternalChanges); addTestCreator(createClangdTestFindReferences); addTestCreator(createClangdTestFollowSymbol); addTestCreator(createClangdTestHighlighting); addTestCreator(createClangdTestIndirectChanges); addTestCreator(createClangdTestLocalReferences); addTestCreator(createClangdTestTooltips); addTestCreator(createClangFixItTest); #endif } void ClangCodeModelPlugin::generateCompilationDB() { using namespace CppEditor; Target *target = ProjectManager::startupTarget(); if (!target) return; const auto projectInfo = CppModelManager::projectInfo(target->project()); if (!projectInfo) return; FilePath baseDir = projectInfo->buildRoot(); if (baseDir == target->project()->projectDirectory()) baseDir = TemporaryDirectory::masterDirectoryFilePath(); QFuture task = Utils::asyncRun(&Internal::generateCompilationDB, ProjectInfoList{projectInfo}, baseDir, CompilationDbPurpose::Project, warningsConfigForProject(target->project()), globalClangOptions(), FilePath()); ProgressManager::addTask(task, Tr::tr("Generating Compilation DB"), "generate compilation db"); m_generatorWatcher.setFuture(task); } void ClangCodeModelPlugin::createCompilationDBAction() { // generate compile_commands.json ActionBuilder(this, Constants::GENERATE_COMPILATION_DB) .setParameterText(Tr::tr("Generate Compilation Database for \"%1\""), Tr::tr("Generate Compilation Database"), ActionBuilder::AlwaysEnabled) .bindContextAction(&m_generateCompilationDBAction) .setCommandAttribute(Command::CA_UpdateText) .setCommandDescription(m_generateCompilationDBAction->text()); if (Project *startupProject = ProjectManager::startupProject()) m_generateCompilationDBAction->setParameter(startupProject->displayName()); connect(&m_generatorWatcher, &QFutureWatcher::finished, this, [this] { const GenerateCompilationDbResult result = m_generatorWatcher.result(); QString message; if (result.error.isEmpty()) { message = Tr::tr("Clang compilation database generated at \"%1\".") .arg(QDir::toNativeSeparators(result.filePath)); } else { message = Tr::tr("Generating Clang compilation database failed: %1").arg(result.error); } MessageManager::writeFlashing(message); m_generateCompilationDBAction->setEnabled(true); }); connect(m_generateCompilationDBAction, &QAction::triggered, this, [this] { if (!m_generateCompilationDBAction->isEnabled()) { MessageManager::writeDisrupting("Cannot generate compilation database: " "Generator is already running."); return; } Project * const project = ProjectManager::startupProject(); if (!project) { MessageManager::writeDisrupting("Cannot generate compilation database: " "No active project."); return; } const CppEditor::ProjectInfo::ConstPtr projectInfo = CppEditor::CppModelManager::projectInfo(project); if (!projectInfo || projectInfo->projectParts().isEmpty()) { MessageManager::writeDisrupting("Cannot generate compilation database: " "Project has no C/C++ project parts."); return; } m_generateCompilationDBAction->setEnabled(false); generateCompilationDB(); }); connect(CppEditor::CppModelManager::instance(), &CppEditor::CppModelManager::projectPartsUpdated, this, [this](Project *project) { if (project != ProjectManager::startupProject()) return; m_generateCompilationDBAction->setParameter(project->displayName()); }); connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, [this](Project *project) { m_generateCompilationDBAction->setParameter(project ? project->displayName() : ""); }); connect(ProjectManager::instance(), &ProjectManager::projectDisplayNameChanged, this, [this](Project *project) { if (project != ProjectManager::startupProject()) return; m_generateCompilationDBAction->setParameter(project->displayName()); }); connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [this](Project *project) { project->registerGenerator(Constants::GENERATE_COMPILATION_DB, m_generateCompilationDBAction->text(), [this] { m_generateCompilationDBAction->trigger(); }); }); } } // namespace ClangCodeModel::Internal #include "clangcodemodelplugin.moc"