ClangCodeModel: Minimize QStringList -> QJsonArray conversions

... when setting up the compilation database.
As it turns out, these conversions were the most expensive part of
creating the JSON file. We now build the JSON arrays incrementally
instead of setting them up from scratch for every source file.

Change-Id: I1e664a6320d5b3c49b31366c58aa14f63818e008
Reviewed-by: David Schulz <david.schulz@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Christian Kandeler
2022-05-05 17:34:31 +02:00
parent 3ce7ca7242
commit 3d1ba205d0
3 changed files with 71 additions and 26 deletions

View File

@@ -1453,13 +1453,13 @@ private:
};
static void addToCompilationDb(QJsonObject &cdb,
const CppEditor::CompilerOptionsBuilder &optionsBuilder,
const CppEditor::ProjectPart &projectPart,
CppEditor::UsePrecompiledHeaders usePch,
const QStringList &projectOptions,
const QJsonArray &projectPartOptions,
const Utils::FilePath &workingDir,
const CppEditor::ProjectFile &sourceFile)
{
QStringList args = clangOptionsForFile(optionsBuilder, sourceFile, projectOptions, usePch);
QJsonArray args = clangOptionsForFile(sourceFile, projectPart, projectPartOptions, usePch);
// TODO: clangd seems to apply some heuristics depending on what we put here.
// Should we make use of them or keep using our own?
@@ -1469,7 +1469,7 @@ static void addToCompilationDb(QJsonObject &cdb,
args.append(fileString);
QJsonObject value;
value.insert("workingDirectory", workingDir.toString());
value.insert("compilationCommand", QJsonArray::fromStringList(args));
value.insert("compilationCommand", args);
cdb.insert(fileString, value);
}
@@ -1497,9 +1497,11 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
*CppEditor::CppModelManager::instance()->fallbackProjectPart(),
warningsConfig);
const CppEditor::UsePrecompiledHeaders usePch = CppEditor::getPchUsage();
const QStringList clangOptions = clangOptionsForFile(
optionsBuilder, {}, optionsForProject(nullptr, warningsConfig), usePch);
initOptions.insert("fallbackFlags", QJsonArray::fromStringList(clangOptions));
const QJsonArray projectPartOptions = fullProjectPartOptions(
optionsBuilder, optionsForProject(nullptr, warningsConfig));
const QJsonArray clangOptions = clangOptionsForFile({}, optionsBuilder.projectPart(),
projectPartOptions, usePch);
initOptions.insert("fallbackFlags", clangOptions);
setInitializationOptions(initOptions);
}
auto isRunningClangdClient = [](const LanguageClient::Client *c) {
@@ -1921,8 +1923,10 @@ void ClangdClient::updateParserConfig(const Utils::FilePath &filePath,
warningsConfig);
const CppEditor::ProjectFile file(filePath.toString(),
CppEditor::ProjectFile::classify(filePath.toString()));
addToCompilationDb(cdbChanges, optionsBuilder, CppEditor::getPchUsage(),
optionsForProject(project(), warningsConfig), filePath.parentDir(), file);
const QJsonArray projectPartOptions = fullProjectPartOptions(
optionsBuilder, optionsForProject(project(), warningsConfig));
addToCompilationDb(cdbChanges, *projectPart, CppEditor::getPchUsage(), projectPartOptions,
filePath.parentDir(), file);
QJsonObject settings;
addCompilationDb(settings, cdbChanges);
DidChangeConfigurationParams configChangeParams;

View File

@@ -183,11 +183,10 @@ static QStringList projectPartArguments(const ProjectPart &projectPart)
static QJsonObject createFileObject(const FilePath &buildDir,
const QStringList &arguments,
const CompilerOptionsBuilder &optionsBuilder,
const ProjectPart &projectPart,
const ProjectFile &projFile,
CompilationDbPurpose purpose,
const QStringList &projectOptions,
const QJsonArray &projectPartOptions,
UsePrecompiledHeaders usePch)
{
QJsonObject fileObject;
@@ -213,8 +212,7 @@ static QJsonObject createFileObject(const FilePath &buildDir,
args.append(langOptionPart);
}
} else {
args = QJsonArray::fromStringList(clangOptionsForFile(optionsBuilder, projFile,
projectOptions, usePch));
args = clangOptionsForFile(projFile, projectPart, projectPartOptions, usePch);
args.prepend("clang"); // TODO: clang-cl for MSVC targets? Does it matter at all what we put here?
}
@@ -245,15 +243,20 @@ GenerateCompilationDbResult generateCompilationDB(const CppEditor::ProjectInfo::
compileCommandsFile.write("[");
const UsePrecompiledHeaders usePch = getPchUsage();
const QJsonArray jsonProjectOptions = QJsonArray::fromStringList(projectOptions);
for (ProjectPart::ConstPtr projectPart : projectInfo->projectParts()) {
QStringList args;
const CompilerOptionsBuilder optionsBuilder = clangOptionsBuilder(*projectPart,
warningsConfig);
if (purpose == CompilationDbPurpose::Project)
QJsonArray ppOptions;
if (purpose == CompilationDbPurpose::Project) {
args = projectPartArguments(*projectPart);
} else {
ppOptions = fullProjectPartOptions(projectPartOptions(optionsBuilder), jsonProjectOptions);
}
for (const ProjectFile &projFile : projectPart->files) {
const QJsonObject json = createFileObject(baseDir, args, optionsBuilder, *projectPart,
projFile, purpose, projectOptions, usePch);
const QJsonObject json = createFileObject(baseDir, args, *projectPart, projFile,
purpose, ppOptions, usePch);
if (compileCommandsFile.size() > 1)
compileCommandsFile.write(",");
compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed());
@@ -332,25 +335,28 @@ static ClangProjectSettings &getProjectSettings(ProjectExplorer::Project *projec
QTC_CHECK(project);
return ClangModelManagerSupport::instance()->projectSettings(project);
}
} // namespace
QStringList clangOptionsForFile(CompilerOptionsBuilder optionsBuilder,
const ProjectFile &file, const QStringList &projectOptions,
UsePrecompiledHeaders usePch)
QJsonArray clangOptionsForFile(const ProjectFile &file, const ProjectPart &projectPart,
const QJsonArray &generalOptions, UsePrecompiledHeaders usePch)
{
CompilerOptionsBuilder optionsBuilder(projectPart);
ProjectFile::Kind fileKind = file.kind;
if (fileKind == ProjectFile::AmbiguousHeader) {
fileKind = optionsBuilder.projectPart().languageVersion <= LanguageVersion::LatestC
fileKind = projectPart.languageVersion <= LanguageVersion::LatestC
? ProjectFile::CHeader : ProjectFile::CXXHeader;
}
if (usePch == UsePrecompiledHeaders::Yes
&& optionsBuilder.projectPart().precompiledHeaders.contains(file.path)) {
&& projectPart.precompiledHeaders.contains(file.path)) {
usePch = UsePrecompiledHeaders::No;
}
optionsBuilder.updateFileLanguage(file.kind);
optionsBuilder.addPrecompiledHeaderOptions(usePch);
return projectOptions + optionsBuilder.options();
const QJsonArray specificOptions = QJsonArray::fromStringList(optionsBuilder.options());
QJsonArray fullOptions = generalOptions;
for (const QJsonValue &opt : specificOptions)
fullOptions << opt;
return fullOptions;
}
ClangDiagnosticConfig warningsConfigForProject(Project *project)
@@ -449,5 +455,34 @@ CompilerOptionsBuilder clangOptionsBuilder(const ProjectPart &projectPart,
return optionsBuilder;
}
QJsonArray projectPartOptions(const CppEditor::CompilerOptionsBuilder &optionsBuilder)
{
const QStringList optionsList = optionsBuilder.options();
QJsonArray optionsArray;
for (const QString &opt : optionsList) {
// These will be added later by the file-specific code, and they trigger warnings
// if they appear twice; see QTCREATORBUG-26664.
if (opt != "-TP" && opt != "-TC")
optionsArray << opt;
}
return optionsArray;
}
QJsonArray fullProjectPartOptions(const CppEditor::CompilerOptionsBuilder &optionsBuilder,
const QStringList &projectOptions)
{
return fullProjectPartOptions(projectPartOptions(optionsBuilder),
QJsonArray::fromStringList(projectOptions));
}
QJsonArray fullProjectPartOptions(const QJsonArray &projectPartOptions,
const QJsonArray &projectOptions)
{
QJsonArray fullProjectPartOptions = projectPartOptions;
for (const QJsonValue &opt : projectOptions)
fullProjectPartOptions.prepend(opt);
return fullProjectPartOptions;
}
} // namespace Internal
} // namespace Clang

View File

@@ -63,9 +63,15 @@ const QStringList optionsForProject(ProjectExplorer::Project *project,
CppEditor::CompilerOptionsBuilder clangOptionsBuilder(
const CppEditor::ProjectPart &projectPart,
const CppEditor::ClangDiagnosticConfig &warningsConfig);
QStringList clangOptionsForFile(CppEditor::CompilerOptionsBuilder optionsBuilder,
const CppEditor::ProjectFile &file,
const QStringList &projectOptions, CppEditor::UsePrecompiledHeaders usePch);
QJsonArray projectPartOptions(const CppEditor::CompilerOptionsBuilder &optionsBuilder);
QJsonArray fullProjectPartOptions(const CppEditor::CompilerOptionsBuilder &optionsBuilder,
const QStringList &projectOptions);
QJsonArray fullProjectPartOptions(const QJsonArray &projectPartOptions,
const QJsonArray &projectOptions);
QJsonArray clangOptionsForFile(const CppEditor::ProjectFile &file,
const CppEditor::ProjectPart &projectPart,
const QJsonArray &generalOptions,
CppEditor::UsePrecompiledHeaders usePch);
CppEditor::ProjectPart::ConstPtr projectPartForFile(const QString &filePath);
CppEditor::ProjectPart::ConstPtr projectPartForFileBasedOnProcessor(const QString &filePath);