diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index d6e7df51e26..283865e80ed 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -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; diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 6f95048daa0..33bb8473a9e 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -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 diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index f1f859dd7cd..b69d99748bb 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -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);