forked from qt-creator/qt-creator
ClangCodeModel: Add experimental clangd support
If the user has enabled clangd (default is off), we start up one instance per project when it is opened/changed (including build config switches), and trigger background indexing. So far, the index is used to provide results for locators and "Find Usages". Per-document functionality such as semantic highlighting and completion is still provided by libclang. Change-Id: I12532fca1b9c6278baab560e7238cba6189cde9f Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
add_qtc_plugin(ClangCodeModel
|
||||
CONDITION TARGET libclang
|
||||
DEPENDS ClangSupport CPlusPlus
|
||||
PLUGIN_DEPENDS Core CppTools TextEditor
|
||||
PLUGIN_DEPENDS Core CppTools LanguageClient TextEditor
|
||||
PLUGIN_TEST_DEPENDS CppEditor QmakeProjectManager
|
||||
SOURCES
|
||||
clangactivationsequencecontextprocessor.cpp clangactivationsequencecontextprocessor.h
|
||||
@@ -29,6 +29,7 @@ add_qtc_plugin(ClangCodeModel
|
||||
clangfixitoperationsextractor.cpp clangfixitoperationsextractor.h
|
||||
clangfollowsymbol.cpp clangfollowsymbol.h
|
||||
clangfunctionhintmodel.cpp clangfunctionhintmodel.h
|
||||
clanggloballocatorfilters.cpp clanggloballocatorfilters.h
|
||||
clanghighlightingresultreporter.cpp clanghighlightingresultreporter.h
|
||||
clanghoverhandler.cpp clanghoverhandler.h
|
||||
clangisdiagnosticrelatedtolocation.h
|
||||
|
||||
@@ -40,7 +40,8 @@ SOURCES += \
|
||||
clangtextmark.cpp \
|
||||
clanguiheaderondiskmanager.cpp \
|
||||
clangutils.cpp \
|
||||
clangoverviewmodel.cpp
|
||||
clangoverviewmodel.cpp \
|
||||
clanggloballocatorfilters.cpp
|
||||
|
||||
HEADERS += \
|
||||
clangactivationsequencecontextprocessor.h \
|
||||
@@ -79,7 +80,8 @@ HEADERS += \
|
||||
clangtextmark.h \
|
||||
clanguiheaderondiskmanager.h \
|
||||
clangutils.h \
|
||||
clangoverviewmodel.h
|
||||
clangoverviewmodel.h \
|
||||
clanggloballocatorfilters.h
|
||||
|
||||
FORMS += clangprojectsettingswidget.ui
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ QtcPlugin {
|
||||
Depends { name: "TextEditor" }
|
||||
Depends { name: "Utils" }
|
||||
Depends { name: "ClangSupport" }
|
||||
Depends { name: "LanguageClient" }
|
||||
|
||||
Depends { name: "libclang"; required: false }
|
||||
Depends { name: "clang_defines" }
|
||||
@@ -72,6 +73,8 @@ QtcPlugin {
|
||||
"clangfollowsymbol.h",
|
||||
"clangfunctionhintmodel.cpp",
|
||||
"clangfunctionhintmodel.h",
|
||||
"clanggloballocatorfilters.cpp",
|
||||
"clanggloballocatorfilters.h",
|
||||
"clanghighlightingresultreporter.cpp",
|
||||
"clanghighlightingresultreporter.h",
|
||||
"clanghoverhandler.cpp",
|
||||
|
||||
@@ -5,6 +5,7 @@ QTC_LIB_DEPENDS += \
|
||||
QTC_PLUGIN_DEPENDS += \
|
||||
coreplugin \
|
||||
cpptools \
|
||||
languageclient \
|
||||
texteditor
|
||||
QTC_TEST_DEPENDS += \
|
||||
cppeditor \
|
||||
|
||||
@@ -77,7 +77,8 @@ void ClangCodeModelPlugin::generateCompilationDB()
|
||||
|
||||
QFuture<GenerateCompilationDbResult> task
|
||||
= QtConcurrent::run(&Internal::generateCompilationDB,
|
||||
CppModelManager::instance()->projectInfo(target->project()));
|
||||
CppModelManager::instance()->projectInfo(target->project()),
|
||||
CompilationDbPurpose::Project);
|
||||
Core::ProgressManager::addTask(task, tr("Generating Compilation DB"), "generate compilation db");
|
||||
m_generatorWatcher.setFuture(task);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include "clangfixitoperationsextractor.h"
|
||||
#include "clangmodelmanagersupport.h"
|
||||
#include "clanghighlightingresultreporter.h"
|
||||
#include "clangprojectsettings.h"
|
||||
#include "clangutils.h"
|
||||
|
||||
#include <diagnosticcontainer.h>
|
||||
@@ -66,12 +65,6 @@
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
static ClangProjectSettings &getProjectSettings(ProjectExplorer::Project *project)
|
||||
{
|
||||
QTC_CHECK(project);
|
||||
return ClangModelManagerSupport::instance()->projectSettings(project);
|
||||
}
|
||||
|
||||
ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
|
||||
BackendCommunicator &communicator,
|
||||
TextEditor::TextDocument *document)
|
||||
@@ -439,123 +432,6 @@ void ClangEditorDocumentProcessor::onParserFinished()
|
||||
updateBackendProjectPartAndDocument();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// TODO: Can we marry this with CompilerOptionsBuilder?
|
||||
class FileOptionsBuilder
|
||||
{
|
||||
public:
|
||||
FileOptionsBuilder(const QString &filePath, CppTools::ProjectPart &projectPart)
|
||||
: m_filePath(filePath)
|
||||
, m_projectPart(projectPart)
|
||||
, m_builder(projectPart)
|
||||
{
|
||||
// Determine the driver mode from toolchain and flags.
|
||||
m_builder.evaluateCompilerFlags();
|
||||
m_isClMode = m_builder.isClStyle();
|
||||
|
||||
addLanguageOptions();
|
||||
addGlobalDiagnosticOptions(); // Before addDiagnosticOptions() so users still can overwrite.
|
||||
addDiagnosticOptions();
|
||||
addGlobalOptions();
|
||||
addPrecompiledHeaderOptions();
|
||||
}
|
||||
|
||||
const QStringList &options() const { return m_options; }
|
||||
const ::Utils::Id &diagnosticConfigId() const { return m_diagnosticConfigId; }
|
||||
CppTools::UseBuildSystemWarnings useBuildSystemWarnings() const
|
||||
{
|
||||
return m_useBuildSystemWarnings;
|
||||
}
|
||||
|
||||
private:
|
||||
void addLanguageOptions()
|
||||
{
|
||||
// Determine file kind with respect to ambiguous headers.
|
||||
CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::classify(m_filePath);
|
||||
if (fileKind == CppTools::ProjectFile::AmbiguousHeader) {
|
||||
fileKind = m_projectPart.languageVersion <= ::Utils::LanguageVersion::LatestC
|
||||
? CppTools::ProjectFile::CHeader
|
||||
: CppTools::ProjectFile::CXXHeader;
|
||||
}
|
||||
|
||||
m_builder.reset();
|
||||
m_builder.updateFileLanguage(fileKind);
|
||||
|
||||
m_options.append(m_builder.options());
|
||||
}
|
||||
|
||||
void addDiagnosticOptions()
|
||||
{
|
||||
if (m_projectPart.project) {
|
||||
ClangProjectSettings &projectSettings = getProjectSettings(m_projectPart.project);
|
||||
if (!projectSettings.useGlobalConfig()) {
|
||||
const ::Utils::Id warningConfigId = projectSettings.warningConfigId();
|
||||
const CppTools::ClangDiagnosticConfigsModel configsModel
|
||||
= CppTools::diagnosticConfigsModel();
|
||||
if (configsModel.hasConfigWithId(warningConfigId)) {
|
||||
addDiagnosticOptionsForConfig(configsModel.configWithId(warningConfigId));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDiagnosticOptionsForConfig(CppTools::codeModelSettings()->clangDiagnosticConfig());
|
||||
}
|
||||
|
||||
void addDiagnosticOptionsForConfig(const CppTools::ClangDiagnosticConfig &diagnosticConfig)
|
||||
{
|
||||
m_diagnosticConfigId = diagnosticConfig.id();
|
||||
m_useBuildSystemWarnings = diagnosticConfig.useBuildSystemWarnings()
|
||||
? CppTools::UseBuildSystemWarnings::Yes
|
||||
: CppTools::UseBuildSystemWarnings::No;
|
||||
|
||||
const QStringList options = m_isClMode
|
||||
? CppTools::clangArgsForCl(diagnosticConfig.clangOptions())
|
||||
: diagnosticConfig.clangOptions();
|
||||
m_options.append(options);
|
||||
}
|
||||
|
||||
void addGlobalDiagnosticOptions()
|
||||
{
|
||||
m_options += CppTools::ClangDiagnosticConfigsModel::globalDiagnosticOptions();
|
||||
}
|
||||
|
||||
void addGlobalOptions()
|
||||
{
|
||||
if (!m_projectPart.project)
|
||||
m_options.append(ClangProjectSettings::globalCommandLineOptions());
|
||||
else
|
||||
m_options.append(getProjectSettings(m_projectPart.project).commandLineOptions());
|
||||
}
|
||||
|
||||
void addPrecompiledHeaderOptions()
|
||||
{
|
||||
using namespace CppTools;
|
||||
|
||||
if (getPchUsage() == UsePrecompiledHeaders::No)
|
||||
return;
|
||||
|
||||
if (m_projectPart.precompiledHeaders.contains(m_filePath))
|
||||
return;
|
||||
|
||||
m_builder.reset();
|
||||
m_builder.addPrecompiledHeaderOptions(UsePrecompiledHeaders::Yes);
|
||||
|
||||
m_options.append(m_builder.options());
|
||||
}
|
||||
|
||||
private:
|
||||
const QString &m_filePath;
|
||||
const CppTools::ProjectPart &m_projectPart;
|
||||
|
||||
::Utils::Id m_diagnosticConfigId;
|
||||
CppTools::UseBuildSystemWarnings m_useBuildSystemWarnings = CppTools::UseBuildSystemWarnings::No;
|
||||
CppTools::CompilerOptionsBuilder m_builder;
|
||||
bool m_isClMode = false;
|
||||
QStringList m_options;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void ClangEditorDocumentProcessor::updateBackendDocument(CppTools::ProjectPart &projectPart)
|
||||
{
|
||||
// On registration we send the document content immediately as an unsaved
|
||||
@@ -572,17 +448,11 @@ void ClangEditorDocumentProcessor::updateBackendDocument(CppTools::ProjectPart &
|
||||
return;
|
||||
}
|
||||
|
||||
const FileOptionsBuilder fileOptions(filePath(), projectPart);
|
||||
m_diagnosticConfigId = fileOptions.diagnosticConfigId();
|
||||
|
||||
const QStringList projectPartOptions = createClangOptions(
|
||||
projectPart, fileOptions.useBuildSystemWarnings(),
|
||||
CppTools::ProjectFile::Unsupported); // No language option as FileOptionsBuilder adds it.
|
||||
|
||||
const QStringList compilationArguments = projectPartOptions + fileOptions.options();
|
||||
const auto clangOptions = createClangOptions(projectPart, filePath());
|
||||
m_diagnosticConfigId = clangOptions.first;
|
||||
|
||||
m_communicator.documentsOpened(
|
||||
{fileContainerWithOptionsAndDocumentContent(compilationArguments, projectPart.headerPaths)});
|
||||
{fileContainerWithOptionsAndDocumentContent(clangOptions.second, projectPart.headerPaths)});
|
||||
setLastSentDocumentRevision(filePath(), revision());
|
||||
}
|
||||
|
||||
|
||||
213
src/plugins/clangcodemodel/clanggloballocatorfilters.cpp
Normal file
213
src/plugins/clangcodemodel/clanggloballocatorfilters.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 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 "clanggloballocatorfilters.h"
|
||||
|
||||
#include "clangmodelmanagersupport.h"
|
||||
|
||||
#include <cpptools/cppclassesfilter.h>
|
||||
#include <cpptools/cppfunctionsfilter.h>
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/cpptoolsconstants.h>
|
||||
#include <cpptools/indexitem.h>
|
||||
#include <languageclient/locatorfilter.h>
|
||||
#include <projectexplorer/session.h>
|
||||
#include <utils/link.h>
|
||||
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
class CppLocatorFilter : public CppTools::CppLocatorFilter
|
||||
{
|
||||
public:
|
||||
CppLocatorFilter()
|
||||
: CppTools::CppLocatorFilter(CppTools::CppModelManager::instance()->locatorData())
|
||||
{
|
||||
setId({});
|
||||
setDisplayName({});
|
||||
setDefaultShortcutString({});
|
||||
setEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
class LspWorkspaceFilter : public LanguageClient::WorkspaceLocatorFilter
|
||||
{
|
||||
public:
|
||||
LspWorkspaceFilter()
|
||||
{
|
||||
setId({});
|
||||
setDisplayName({});
|
||||
setDefaultShortcutString({});
|
||||
setEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CppClassesFilter : public CppTools::CppClassesFilter
|
||||
{
|
||||
public:
|
||||
CppClassesFilter()
|
||||
: CppTools::CppClassesFilter(CppTools::CppModelManager::instance()->locatorData())
|
||||
{
|
||||
setId({});
|
||||
setDisplayName({});
|
||||
setDefaultShortcutString({});
|
||||
setEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
class LspClassesFilter : public LanguageClient::WorkspaceClassLocatorFilter
|
||||
{
|
||||
public:
|
||||
LspClassesFilter() {
|
||||
setId({});
|
||||
setDisplayName({});
|
||||
setDefaultShortcutString({});
|
||||
setEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
class CppFunctionsFilter : public CppTools::CppFunctionsFilter
|
||||
{
|
||||
public:
|
||||
CppFunctionsFilter()
|
||||
: CppTools::CppFunctionsFilter(CppTools::CppModelManager::instance()->locatorData())
|
||||
{
|
||||
setId({});
|
||||
setDisplayName({});
|
||||
setDefaultShortcutString({});
|
||||
setEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
class LspFunctionsFilter : public LanguageClient::WorkspaceMethodLocatorFilter
|
||||
{
|
||||
public:
|
||||
LspFunctionsFilter()
|
||||
{
|
||||
setId({});
|
||||
setDisplayName({});
|
||||
setDefaultShortcutString({});
|
||||
setEnabled(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ClangGlobalSymbolFilter::ClangGlobalSymbolFilter()
|
||||
: ClangGlobalSymbolFilter(new CppLocatorFilter, new LspWorkspaceFilter)
|
||||
{
|
||||
}
|
||||
|
||||
ClangGlobalSymbolFilter::ClangGlobalSymbolFilter(ILocatorFilter *cppFilter,
|
||||
ILocatorFilter *lspFilter)
|
||||
: m_cppFilter(cppFilter), m_lspFilter(lspFilter)
|
||||
{
|
||||
setId(CppTools::Constants::LOCATOR_FILTER_ID);
|
||||
setDisplayName(CppTools::Constants::LOCATOR_FILTER_DISPLAY_NAME);
|
||||
setDefaultShortcutString(":");
|
||||
setDefaultIncludedByDefault(false);
|
||||
}
|
||||
|
||||
ClangGlobalSymbolFilter::~ClangGlobalSymbolFilter()
|
||||
{
|
||||
delete m_cppFilter;
|
||||
delete m_lspFilter;
|
||||
}
|
||||
|
||||
void ClangGlobalSymbolFilter::prepareSearch(const QString &entry)
|
||||
{
|
||||
m_cppFilter->prepareSearch(entry);
|
||||
QVector<LanguageClient::Client *> clients;
|
||||
for (ProjectExplorer::Project * const project : ProjectExplorer::SessionManager::projects()) {
|
||||
LanguageClient::Client * const client
|
||||
= ClangModelManagerSupport::instance()->clientForProject(project);
|
||||
if (client)
|
||||
clients << client;
|
||||
}
|
||||
if (!clients.isEmpty()) {
|
||||
static_cast<LanguageClient::WorkspaceLocatorFilter *>(m_lspFilter)
|
||||
->prepareSearch(entry, clients);
|
||||
}
|
||||
}
|
||||
|
||||
QList<Core::LocatorFilterEntry> ClangGlobalSymbolFilter::matchesFor(
|
||||
QFutureInterface<Core::LocatorFilterEntry> &future, const QString &entry)
|
||||
{
|
||||
QList<Core::LocatorFilterEntry> matches = m_cppFilter->matchesFor(future, entry);
|
||||
const QList<Core::LocatorFilterEntry> lspMatches = m_lspFilter->matchesFor(future, entry);
|
||||
if (!lspMatches.isEmpty()) {
|
||||
std::set<std::tuple<QString, int, int>> locations;
|
||||
for (const auto &entry : qAsConst(matches)) {
|
||||
const CppTools::IndexItem::Ptr item
|
||||
= qvariant_cast<CppTools::IndexItem::Ptr>(entry.internalData);
|
||||
locations.insert(std::make_tuple(item->fileName(), item->line(), item->column()));
|
||||
}
|
||||
for (const auto &entry : lspMatches) {
|
||||
if (!entry.internalData.canConvert<Utils::Link>())
|
||||
continue;
|
||||
const auto link = qvariant_cast<Utils::Link>(entry.internalData);
|
||||
if (locations.find(std::make_tuple(link.targetFileName, link.targetLine,
|
||||
link.targetColumn)) == locations.cend()) {
|
||||
matches << entry; // TODO: Insert sorted?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
void ClangGlobalSymbolFilter::accept(Core::LocatorFilterEntry selection, QString *newText,
|
||||
int *selectionStart, int *selectionLength) const
|
||||
{
|
||||
if (qvariant_cast<CppTools::IndexItem::Ptr>(selection.internalData))
|
||||
m_cppFilter->accept(selection, newText, selectionStart, selectionLength);
|
||||
else
|
||||
m_lspFilter->accept(selection, newText, selectionStart, selectionLength);
|
||||
}
|
||||
|
||||
|
||||
ClangClassesFilter::ClangClassesFilter()
|
||||
: ClangGlobalSymbolFilter(new CppClassesFilter, new LspClassesFilter)
|
||||
{
|
||||
setId(CppTools::Constants::CLASSES_FILTER_ID);
|
||||
setDisplayName(CppTools::Constants::CLASSES_FILTER_DISPLAY_NAME);
|
||||
setDefaultShortcutString("c");
|
||||
setDefaultIncludedByDefault(false);
|
||||
}
|
||||
|
||||
ClangFunctionsFilter::ClangFunctionsFilter()
|
||||
: ClangGlobalSymbolFilter(new CppFunctionsFilter, new LspFunctionsFilter)
|
||||
{
|
||||
setId(CppTools::Constants::FUNCTIONS_FILTER_ID);
|
||||
setDisplayName(CppTools::Constants::FUNCTIONS_FILTER_DISPLAY_NAME);
|
||||
setDefaultShortcutString("m");
|
||||
setDefaultIncludedByDefault(false);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
64
src/plugins/clangcodemodel/clanggloballocatorfilters.h
Normal file
64
src/plugins/clangcodemodel/clanggloballocatorfilters.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 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.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <coreplugin/locator/ilocatorfilter.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
class ClangGlobalSymbolFilter : public Core::ILocatorFilter
|
||||
{
|
||||
public:
|
||||
ClangGlobalSymbolFilter();
|
||||
ClangGlobalSymbolFilter(Core::ILocatorFilter *cppFilter, Core::ILocatorFilter *lspFilter);
|
||||
~ClangGlobalSymbolFilter() override;
|
||||
|
||||
private:
|
||||
void prepareSearch(const QString &entry) override;
|
||||
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
|
||||
const QString &entry) override;
|
||||
void accept(Core::LocatorFilterEntry selection, QString *newText,
|
||||
int *selectionStart, int *selectionLength) const override;
|
||||
|
||||
Core::ILocatorFilter * const m_cppFilter;
|
||||
Core::ILocatorFilter * const m_lspFilter;
|
||||
};
|
||||
|
||||
class ClangClassesFilter : public ClangGlobalSymbolFilter
|
||||
{
|
||||
public:
|
||||
ClangClassesFilter();
|
||||
};
|
||||
|
||||
class ClangFunctionsFilter : public ClangGlobalSymbolFilter
|
||||
{
|
||||
public:
|
||||
ClangFunctionsFilter();
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
@@ -33,9 +33,12 @@
|
||||
#include "clangprojectsettings.h"
|
||||
#include "clangrefactoringengine.h"
|
||||
#include "clangcurrentdocumentfilter.h"
|
||||
#include "clanggloballocatorfilters.h"
|
||||
#include "clangoverviewmodel.h"
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
|
||||
#include <cpptools/cppcodemodelsettings.h>
|
||||
#include <cpptools/cppfollowsymbolundercursor.h>
|
||||
@@ -44,23 +47,34 @@
|
||||
#include <cpptools/editordocumenthandle.h>
|
||||
#include <cpptools/projectinfo.h>
|
||||
|
||||
#include <languageclient/client.h>
|
||||
#include <languageclient/languageclientinterface.h>
|
||||
#include <languageclient/languageclientmanager.h>
|
||||
|
||||
#include <texteditor/quickfix.h>
|
||||
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectnodes.h>
|
||||
#include <projectexplorer/session.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <clangsupport/filecontainer.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QMenu>
|
||||
#include <QTextBlock>
|
||||
#include <QTimer>
|
||||
|
||||
using namespace ClangCodeModel;
|
||||
using namespace ClangCodeModel::Internal;
|
||||
using namespace LanguageClient;
|
||||
|
||||
static Q_LOGGING_CATEGORY(clangdLog, "qtc.clangcodemodel.clangd", QtWarningMsg);
|
||||
static ClangModelManagerSupport *m_instance = nullptr;
|
||||
|
||||
static CppTools::CppModelManager *cppModelManager()
|
||||
@@ -79,6 +93,9 @@ ClangModelManagerSupport::ClangModelManagerSupport()
|
||||
|
||||
CppTools::CppModelManager::instance()->setCurrentDocumentFilter(
|
||||
std::make_unique<ClangCurrentDocumentFilter>());
|
||||
cppModelManager()->setLocatorFilter(std::make_unique<ClangGlobalSymbolFilter>());
|
||||
cppModelManager()->setClassesFilter(std::make_unique<ClangClassesFilter>());
|
||||
cppModelManager()->setFunctionsFilter(std::make_unique<ClangFunctionsFilter>());
|
||||
|
||||
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
||||
connect(editorManager, &Core::EditorManager::editorOpened,
|
||||
@@ -104,9 +121,14 @@ ClangModelManagerSupport::ClangModelManagerSupport()
|
||||
connect(sessionManager, &ProjectExplorer::SessionManager::aboutToRemoveProject,
|
||||
this, &ClangModelManagerSupport::onAboutToRemoveProject);
|
||||
|
||||
CppTools::CppCodeModelSettings::setDefaultClangdPath(Utils::FilePath::fromString(
|
||||
Core::ICore::clangdExecutable(CLANG_BINDIR)));
|
||||
CppTools::CppCodeModelSettings *settings = CppTools::codeModelSettings();
|
||||
connect(settings, &CppTools::CppCodeModelSettings::clangDiagnosticConfigsInvalidated,
|
||||
this, &ClangModelManagerSupport::onDiagnosticConfigsInvalidated);
|
||||
|
||||
// TODO: Enable this once we do document-level stuff with clangd (highlighting etc)
|
||||
// createClient(nullptr, {});
|
||||
}
|
||||
|
||||
ClangModelManagerSupport::~ClangModelManagerSupport()
|
||||
@@ -220,6 +242,136 @@ void ClangModelManagerSupport::connectToWidgetsMarkContextMenuRequested(QWidget
|
||||
}
|
||||
}
|
||||
|
||||
static QString clientName() { return "ccm-clangd"; }
|
||||
|
||||
void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *project,
|
||||
const CppTools::ProjectInfo &projectInfo)
|
||||
{
|
||||
if (!CppTools::codeModelSettings()->useClangd())
|
||||
return;
|
||||
const auto getJsonDbDir = [project] {
|
||||
if (const ProjectExplorer::Target * const target = project->activeTarget()) {
|
||||
if (const ProjectExplorer::BuildConfiguration * const bc
|
||||
= target->activeBuildConfiguration()) {
|
||||
return bc->buildDirectory();
|
||||
}
|
||||
}
|
||||
return Utils::FilePath();
|
||||
};
|
||||
|
||||
const Utils::FilePath jsonDbDir = getJsonDbDir();
|
||||
if (jsonDbDir.isEmpty())
|
||||
return;
|
||||
const auto generatorWatcher = new QFutureWatcher<GenerateCompilationDbResult>;
|
||||
connect(generatorWatcher, &QFutureWatcher<GenerateCompilationDbResult>::finished,
|
||||
[this, project, projectInfo, getJsonDbDir, jsonDbDir, generatorWatcher] {
|
||||
generatorWatcher->deleteLater();
|
||||
if (!CppTools::codeModelSettings()->useClangd())
|
||||
return;
|
||||
if (!ProjectExplorer::SessionManager::hasProject(project))
|
||||
return;
|
||||
if (cppModelManager()->projectInfo(project) != projectInfo)
|
||||
return;
|
||||
if (getJsonDbDir() != jsonDbDir)
|
||||
return;
|
||||
const GenerateCompilationDbResult result = generatorWatcher->result();
|
||||
if (!result.error.isEmpty()) {
|
||||
Core::MessageManager::writeDisrupting(
|
||||
tr("Cannot use clangd: Failed to generate compilation database:\n%1")
|
||||
.arg(result.error));
|
||||
return;
|
||||
}
|
||||
if (Client * const oldClient = clientForProject(project))
|
||||
LanguageClientManager::shutdownClient(oldClient);
|
||||
Client * const client = createClient(project, jsonDbDir);
|
||||
connect(client, &Client::initialized, this, [client, project, projectInfo, jsonDbDir] {
|
||||
using namespace ProjectExplorer;
|
||||
if (!CppTools::codeModelSettings()->useClangd())
|
||||
return;
|
||||
if (!SessionManager::hasProject(project))
|
||||
return;
|
||||
if (cppModelManager()->projectInfo(project) != projectInfo)
|
||||
return;
|
||||
|
||||
// TODO: We'd like to add all open editor documents for the project to the client here,
|
||||
// but there doesn't seem to be such an interface.
|
||||
|
||||
// clangd oddity: Background indexing only starts after opening a random file.
|
||||
// TODO: changes to the compilation db do not seem to trigger re-indexing.
|
||||
// How to force it?
|
||||
ProjectNode * const rootNode = project->rootProjectNode();
|
||||
if (!rootNode)
|
||||
return;
|
||||
const Node * const cxxNode = rootNode->findNode([](Node *n) {
|
||||
const FileNode * const fileNode = n->asFileNode();
|
||||
return fileNode && (fileNode->fileType() == FileType::Source
|
||||
|| fileNode->fileType() == FileType::Header)
|
||||
&& fileNode->filePath().exists();
|
||||
});
|
||||
if (!cxxNode)
|
||||
return;
|
||||
|
||||
QFile cxxFile(cxxNode->filePath().toString());
|
||||
if (!cxxFile.open(QIODevice::ReadOnly))
|
||||
return;
|
||||
using namespace LanguageServerProtocol;
|
||||
TextDocumentItem item;
|
||||
item.setLanguageId("text/x-c++src");
|
||||
item.setUri(DocumentUri::fromFilePath(cxxNode->filePath()));
|
||||
item.setText(QString::fromUtf8(cxxFile.readAll()));
|
||||
item.setVersion(0);
|
||||
client->sendContent(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)));
|
||||
client->sendContent(DidCloseTextDocumentNotification(DidCloseTextDocumentParams(
|
||||
TextDocumentIdentifier{item.uri()})));
|
||||
});
|
||||
|
||||
});
|
||||
generatorWatcher->setFuture(Utils::runAsync(&Internal::generateCompilationDB, projectInfo,
|
||||
CompilationDbPurpose::CodeModel));
|
||||
}
|
||||
|
||||
LanguageClient::Client *ClangModelManagerSupport::clientForProject(
|
||||
const ProjectExplorer::Project *project)
|
||||
{
|
||||
const QList<Client *> clients = Utils::filtered(
|
||||
LanguageClientManager::clientsForProject(project),
|
||||
[](const LanguageClient::Client *c) {
|
||||
return c->name().startsWith(clientName())
|
||||
&& c->state() != Client::ShutdownRequested
|
||||
&& c->state() != Client::Shutdown;
|
||||
});
|
||||
QTC_CHECK(clients.size() <= 1);
|
||||
return clients.empty() ? nullptr : clients.first();
|
||||
}
|
||||
|
||||
Client *ClangModelManagerSupport::createClient(ProjectExplorer::Project *project,
|
||||
const Utils::FilePath &jsonDbDir)
|
||||
{
|
||||
QString clangdArgs = "--index --background-index --limit-results=0";
|
||||
if (!jsonDbDir.isEmpty())
|
||||
clangdArgs += " --compile-commands-dir=" + jsonDbDir.toString();
|
||||
if (clangdLog().isDebugEnabled())
|
||||
clangdArgs += " --log=verbose --pretty";
|
||||
const auto clientInterface = new StdIOClientInterface;
|
||||
clientInterface->setExecutable(CppTools::codeModelSettings()->clangdFilePath().toString());
|
||||
clientInterface->setArguments(clangdArgs);
|
||||
const auto client = new Client(clientInterface);
|
||||
client->setName(clientName());
|
||||
LanguageFilter langFilter;
|
||||
langFilter.mimeTypes = QStringList{"text/x-chdr", "text/x-c++hdr", "text/x-c++src",
|
||||
"text/x-objc++src", "text/x-objcsrc"};
|
||||
client->setSupportedLanguage(langFilter);
|
||||
LanguageServerProtocol::ClientCapabilities caps = Client::defaultClientCapabilities();
|
||||
caps.clearExperimental();
|
||||
caps.clearTextDocument();
|
||||
client->setClientCapabilities(caps);
|
||||
client->setLocatorsEnabled(false);
|
||||
client->setDocumentActionsEnabled(false);
|
||||
client->setCurrentProject(project);
|
||||
client->start();
|
||||
return client;
|
||||
}
|
||||
|
||||
void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
|
||||
{
|
||||
QTC_ASSERT(editor, return);
|
||||
@@ -232,6 +384,11 @@ void ClangModelManagerSupport::onEditorOpened(Core::IEditor *editor)
|
||||
connectToWidgetsMarkContextMenuRequested(editor->widget());
|
||||
|
||||
// TODO: Ensure that not fully loaded documents are updated?
|
||||
|
||||
ProjectExplorer::Project * const project
|
||||
= ProjectExplorer::SessionManager::projectForFile(document->filePath());
|
||||
if (Client * const client = clientForProject(project))
|
||||
client->openDocument(textDocument);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,6 +577,8 @@ void ClangModelManagerSupport::onProjectPartsUpdated(ProjectExplorer::Project *p
|
||||
const CppTools::ProjectInfo projectInfo = cppModelManager()->projectInfo(project);
|
||||
QTC_ASSERT(projectInfo.isValid(), return);
|
||||
|
||||
updateLanguageClient(project, projectInfo);
|
||||
|
||||
QStringList projectPartIds;
|
||||
for (const CppTools::ProjectPart::Ptr &projectPart : projectInfo.projectParts())
|
||||
projectPartIds.append(projectPart->id());
|
||||
|
||||
@@ -47,6 +47,8 @@ class FollowSymbolInterface;
|
||||
class RefactoringEngineInterface;
|
||||
} // namespace CppTools
|
||||
|
||||
namespace LanguageClient { class Client; }
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
@@ -77,6 +79,8 @@ public:
|
||||
|
||||
ClangProjectSettings &projectSettings(ProjectExplorer::Project *project) const;
|
||||
|
||||
LanguageClient::Client *clientForProject(const ProjectExplorer::Project *project);
|
||||
|
||||
static ClangModelManagerSupport *instance();
|
||||
|
||||
private:
|
||||
@@ -118,6 +122,11 @@ private:
|
||||
void connectToTextDocumentContentsChangedForUnsavedFile(TextEditor::TextDocument *textDocument);
|
||||
void connectToWidgetsMarkContextMenuRequested(QWidget *editorWidget);
|
||||
|
||||
void updateLanguageClient(ProjectExplorer::Project *project,
|
||||
const CppTools::ProjectInfo &projectInfo);
|
||||
LanguageClient::Client *createClient(ProjectExplorer::Project *project,
|
||||
const Utils::FilePath &jsonDbDir);
|
||||
|
||||
private:
|
||||
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
|
||||
BackendCommunicator m_communicator;
|
||||
|
||||
@@ -26,6 +26,12 @@
|
||||
#include "clangrefactoringengine.h"
|
||||
#include "clangeditordocumentprocessor.h"
|
||||
|
||||
#include "clangmodelmanagersupport.h"
|
||||
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <languageclient/client.h>
|
||||
#include <languageclient/languageclientsymbolsupport.h>
|
||||
#include <projectexplorer/session.h>
|
||||
#include <utils/textutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -80,5 +86,27 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data,
|
||||
m_watcher->setFuture(cursorFuture);
|
||||
}
|
||||
|
||||
void RefactoringEngine::findUsages(const CppTools::CursorInEditor &cursor,
|
||||
CppTools::UsagesCallback &&callback) const
|
||||
{
|
||||
ProjectExplorer::Project * const project
|
||||
= ProjectExplorer::SessionManager::projectForFile(cursor.filePath());
|
||||
LanguageClient::Client * const client
|
||||
= ClangModelManagerSupport::instance()->clientForProject(project);
|
||||
if (!client || client->state() != LanguageClient::Client::Initialized) {
|
||||
// TODO: Also forward to built-in if index is not ready.
|
||||
// This requires us to keep track of workDone status in the client.
|
||||
// Related: Also allow to override the server string for progress info
|
||||
CppTools::CppModelManager::builtinRefactoringEngine()
|
||||
->findUsages(cursor, std::move(callback));
|
||||
return;
|
||||
}
|
||||
// TODO: We want to keep our "access type info" feature.
|
||||
// Check whether we can support it using clang 12's textDocument/ast request
|
||||
if (!client->documentOpen(cursor.textDocument()))
|
||||
client->openDocument(cursor.textDocument()); // TODO: Just a workaround
|
||||
client->symbolSupport().findUsages(cursor.textDocument(), cursor.cursor());
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
@@ -46,7 +46,8 @@ public:
|
||||
RenameCallback &&renameSymbolsCallback) override;
|
||||
void globalRename(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&,
|
||||
const QString &) override {}
|
||||
void findUsages(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&) const override {}
|
||||
void findUsages(const CppTools::CursorInEditor &cursor,
|
||||
CppTools::UsagesCallback &&callback) const override;
|
||||
void globalFollowSymbol(const CppTools::CursorInEditor &,
|
||||
::Utils::ProcessLinkCallback &&,
|
||||
const CPlusPlus::Snapshot &,
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "clangeditordocumentprocessor.h"
|
||||
#include "clangmodelmanagersupport.h"
|
||||
#include "clangprojectsettings.h"
|
||||
|
||||
#include <clangsupport/tokeninfocontainer.h>
|
||||
|
||||
@@ -104,14 +105,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
QStringList createClangOptions(const ProjectPart &projectPart,
|
||||
UseBuildSystemWarnings useBuildSystemWarnings,
|
||||
ProjectFile::Kind fileKind)
|
||||
{
|
||||
return LibClangOptionsBuilder(projectPart, useBuildSystemWarnings)
|
||||
.build(fileKind, UsePrecompiledHeaders::No);
|
||||
}
|
||||
|
||||
ProjectPart::Ptr projectPartForFile(const QString &filePath)
|
||||
{
|
||||
if (const auto parser = CppTools::BaseEditorDocumentParser::get(filePath))
|
||||
@@ -354,34 +347,45 @@ static QStringList projectPartArguments(const ProjectPart &projectPart)
|
||||
static QJsonObject createFileObject(const FilePath &buildDir,
|
||||
const QStringList &arguments,
|
||||
const ProjectPart &projectPart,
|
||||
const ProjectFile &projFile)
|
||||
const ProjectFile &projFile,
|
||||
CompilationDbPurpose purpose)
|
||||
{
|
||||
QJsonObject fileObject;
|
||||
fileObject["file"] = projFile.path;
|
||||
QJsonArray args = QJsonArray::fromStringList(arguments);
|
||||
QJsonArray args;
|
||||
|
||||
const ProjectFile::Kind kind = ProjectFile::classify(projFile.path);
|
||||
if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID
|
||||
|| projectPart.toolchainType == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) {
|
||||
if (ProjectFile::isC(kind))
|
||||
args.append("/TC");
|
||||
else if (ProjectFile::isCxx(kind))
|
||||
args.append("/TP");
|
||||
if (purpose == CompilationDbPurpose::Project) {
|
||||
args = QJsonArray::fromStringList(arguments);
|
||||
|
||||
const ProjectFile::Kind kind = ProjectFile::classify(projFile.path);
|
||||
if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID
|
||||
|| projectPart.toolchainType == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) {
|
||||
if (ProjectFile::isC(kind))
|
||||
args.append("/TC");
|
||||
else if (ProjectFile::isCxx(kind))
|
||||
args.append("/TP");
|
||||
} else {
|
||||
QStringList langOption
|
||||
= createLanguageOptionGcc(kind,
|
||||
projectPart.languageExtensions
|
||||
& LanguageExtension::ObjectiveC);
|
||||
for (const QString &langOptionPart : langOption)
|
||||
args.append(langOptionPart);
|
||||
}
|
||||
} else {
|
||||
QStringList langOption
|
||||
= createLanguageOptionGcc(kind,
|
||||
projectPart.languageExtensions
|
||||
& LanguageExtension::ObjectiveC);
|
||||
for (const QString &langOptionPart : langOption)
|
||||
args.append(langOptionPart);
|
||||
// TODO: Do we really need to re-calculate the project part options per source file?
|
||||
args = QJsonArray::fromStringList(createClangOptions(projectPart, projFile.path).second);
|
||||
args.prepend("clang"); // TODO: clang-cl for MSVC targets? Does it matter at all what we put here?
|
||||
}
|
||||
|
||||
args.append(QDir::toNativeSeparators(projFile.path));
|
||||
fileObject["arguments"] = args;
|
||||
fileObject["directory"] = buildDir.toString();
|
||||
return fileObject;
|
||||
}
|
||||
|
||||
GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo)
|
||||
GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo,
|
||||
CompilationDbPurpose purpose)
|
||||
{
|
||||
const FilePath buildDir = buildDirectory(*projectInfo.project());
|
||||
QTC_ASSERT(!buildDir.isEmpty(), return GenerateCompilationDbResult(QString(),
|
||||
@@ -400,9 +404,12 @@ GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectI
|
||||
compileCommandsFile.write("[");
|
||||
|
||||
for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) {
|
||||
const QStringList args = projectPartArguments(*projectPart);
|
||||
QStringList args;
|
||||
if (purpose == CompilationDbPurpose::Project)
|
||||
args = projectPartArguments(*projectPart);
|
||||
for (const ProjectFile &projFile : projectPart->files) {
|
||||
const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile);
|
||||
const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile,
|
||||
purpose);
|
||||
if (compileCommandsFile.size() > 1)
|
||||
compileCommandsFile.write(",");
|
||||
compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed());
|
||||
@@ -474,5 +481,142 @@ QString DiagnosticTextInfo::clazyCheckName(const QString &option)
|
||||
return option;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
static ClangProjectSettings &getProjectSettings(ProjectExplorer::Project *project)
|
||||
{
|
||||
QTC_CHECK(project);
|
||||
return ClangModelManagerSupport::instance()->projectSettings(project);
|
||||
}
|
||||
|
||||
// TODO: Can we marry this with CompilerOptionsBuilder?
|
||||
class FileOptionsBuilder
|
||||
{
|
||||
public:
|
||||
FileOptionsBuilder(const QString &filePath, const CppTools::ProjectPart &projectPart)
|
||||
: m_filePath(filePath)
|
||||
, m_projectPart(projectPart)
|
||||
, m_builder(projectPart)
|
||||
{
|
||||
// Determine the driver mode from toolchain and flags.
|
||||
m_builder.evaluateCompilerFlags();
|
||||
m_isClMode = m_builder.isClStyle();
|
||||
|
||||
addLanguageOptions();
|
||||
addGlobalDiagnosticOptions(); // Before addDiagnosticOptions() so users still can overwrite.
|
||||
addDiagnosticOptions();
|
||||
addGlobalOptions();
|
||||
addPrecompiledHeaderOptions();
|
||||
}
|
||||
|
||||
const QStringList &options() const { return m_options; }
|
||||
const ::Utils::Id &diagnosticConfigId() const { return m_diagnosticConfigId; }
|
||||
CppTools::UseBuildSystemWarnings useBuildSystemWarnings() const
|
||||
{
|
||||
return m_useBuildSystemWarnings;
|
||||
}
|
||||
|
||||
private:
|
||||
void addLanguageOptions()
|
||||
{
|
||||
// Determine file kind with respect to ambiguous headers.
|
||||
CppTools::ProjectFile::Kind fileKind = CppTools::ProjectFile::classify(m_filePath);
|
||||
if (fileKind == CppTools::ProjectFile::AmbiguousHeader) {
|
||||
fileKind = m_projectPart.languageVersion <= ::Utils::LanguageVersion::LatestC
|
||||
? CppTools::ProjectFile::CHeader
|
||||
: CppTools::ProjectFile::CXXHeader;
|
||||
}
|
||||
|
||||
m_builder.reset();
|
||||
m_builder.updateFileLanguage(fileKind);
|
||||
|
||||
m_options.append(m_builder.options());
|
||||
}
|
||||
|
||||
void addDiagnosticOptions()
|
||||
{
|
||||
if (m_projectPart.project) {
|
||||
ClangProjectSettings &projectSettings = getProjectSettings(m_projectPart.project);
|
||||
if (!projectSettings.useGlobalConfig()) {
|
||||
const ::Utils::Id warningConfigId = projectSettings.warningConfigId();
|
||||
const CppTools::ClangDiagnosticConfigsModel configsModel
|
||||
= CppTools::diagnosticConfigsModel();
|
||||
if (configsModel.hasConfigWithId(warningConfigId)) {
|
||||
addDiagnosticOptionsForConfig(configsModel.configWithId(warningConfigId));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDiagnosticOptionsForConfig(CppTools::codeModelSettings()->clangDiagnosticConfig());
|
||||
}
|
||||
|
||||
void addDiagnosticOptionsForConfig(const CppTools::ClangDiagnosticConfig &diagnosticConfig)
|
||||
{
|
||||
m_diagnosticConfigId = diagnosticConfig.id();
|
||||
m_useBuildSystemWarnings = diagnosticConfig.useBuildSystemWarnings()
|
||||
? CppTools::UseBuildSystemWarnings::Yes
|
||||
: CppTools::UseBuildSystemWarnings::No;
|
||||
|
||||
const QStringList options = m_isClMode
|
||||
? CppTools::clangArgsForCl(diagnosticConfig.clangOptions())
|
||||
: diagnosticConfig.clangOptions();
|
||||
m_options.append(options);
|
||||
}
|
||||
|
||||
void addGlobalDiagnosticOptions()
|
||||
{
|
||||
m_options += CppTools::ClangDiagnosticConfigsModel::globalDiagnosticOptions();
|
||||
}
|
||||
|
||||
void addGlobalOptions()
|
||||
{
|
||||
if (!m_projectPart.project)
|
||||
m_options.append(ClangProjectSettings::globalCommandLineOptions());
|
||||
else
|
||||
m_options.append(getProjectSettings(m_projectPart.project).commandLineOptions());
|
||||
}
|
||||
|
||||
void addPrecompiledHeaderOptions()
|
||||
{
|
||||
using namespace CppTools;
|
||||
|
||||
if (getPchUsage() == UsePrecompiledHeaders::No)
|
||||
return;
|
||||
|
||||
if (m_projectPart.precompiledHeaders.contains(m_filePath))
|
||||
return;
|
||||
|
||||
m_builder.reset();
|
||||
m_builder.addPrecompiledHeaderOptions(UsePrecompiledHeaders::Yes);
|
||||
|
||||
m_options.append(m_builder.options());
|
||||
}
|
||||
|
||||
private:
|
||||
const QString &m_filePath;
|
||||
const CppTools::ProjectPart &m_projectPart;
|
||||
|
||||
::Utils::Id m_diagnosticConfigId;
|
||||
CppTools::UseBuildSystemWarnings m_useBuildSystemWarnings = CppTools::UseBuildSystemWarnings::No;
|
||||
CppTools::CompilerOptionsBuilder m_builder;
|
||||
bool m_isClMode = false;
|
||||
QStringList m_options;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
QPair<Utils::Id, QStringList> createClangOptions(const CppTools::ProjectPart &projectPart,
|
||||
const QString &filePath)
|
||||
{
|
||||
QPair<Utils::Id, QStringList> value;
|
||||
const FileOptionsBuilder fileOptions(filePath, projectPart);
|
||||
value.first = fileOptions.diagnosticConfigId();
|
||||
LibClangOptionsBuilder optionsBuilder(projectPart, fileOptions.useBuildSystemWarnings());
|
||||
const QStringList projectPartOptions = optionsBuilder.build(CppTools::ProjectFile::Unsupported,
|
||||
UsePrecompiledHeaders::No);
|
||||
value.second = projectPartOptions + fileOptions.options();
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Clang
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <cpptools/projectpart.h>
|
||||
#include <cpptools/compileroptionsbuilder.h>
|
||||
|
||||
#include <QPair>
|
||||
#include <QTextCursor>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@@ -49,9 +50,8 @@ namespace Internal {
|
||||
CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath);
|
||||
void setLastSentDocumentRevision(const QString &filePath, uint revision);
|
||||
|
||||
QStringList createClangOptions(const CppTools::ProjectPart &projectPart,
|
||||
CppTools::UseBuildSystemWarnings useBuildSystemWarnings,
|
||||
CppTools::ProjectFile::Kind fileKind);
|
||||
QPair<Utils::Id, QStringList> createClangOptions(const CppTools::ProjectPart &projectPart,
|
||||
const QString &filePath);
|
||||
|
||||
CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath);
|
||||
CppTools::ProjectPart::Ptr projectPartForFileBasedOnProcessor(const QString &filePath);
|
||||
@@ -78,7 +78,9 @@ public:
|
||||
QString error;
|
||||
};
|
||||
|
||||
GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo);
|
||||
enum CompilationDbPurpose { Project, CodeModel };
|
||||
GenerateCompilationDbResult generateCompilationDB(CppTools::ProjectInfo projectInfo,
|
||||
CompilationDbPurpose purpose);
|
||||
|
||||
class DiagnosticTextInfo
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user