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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user