summaryrefslogtreecommitdiff
path: root/src/plugins/clangcodemodel/clangutils.cpp
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2021-02-23 13:51:41 +0100
committerChristian Kandeler <christian.kandeler@qt.io>2021-04-22 07:32:58 +0000
commitecafdb7543927ffe8a9066ce24ed532a097fa21d (patch)
tree5f77d9fc9af3967af2bda56c052ccd4a351e0703 /src/plugins/clangcodemodel/clangutils.cpp
parent8bacd9bdc49c376af69c81ac9acf2e9db1f10cb5 (diff)
downloadqt-creator-ecafdb7543927ffe8a9066ce24ed532a097fa21d.tar.gz
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>
Diffstat (limited to 'src/plugins/clangcodemodel/clangutils.cpp')
-rw-r--r--src/plugins/clangcodemodel/clangutils.cpp198
1 files changed, 171 insertions, 27 deletions
diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp
index f46b455197..95b9364e0c 100644
--- a/src/plugins/clangcodemodel/clangutils.cpp
+++ b/src/plugins/clangcodemodel/clangutils.cpp
@@ -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);
-
- 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");
+ QJsonArray args;
+
+ 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