diff options
24 files changed, 430 insertions, 69 deletions
diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 23dd71af16..bf04848652 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -419,7 +419,7 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir, c *CppEditor::CppModelManager::fallbackProjectPart(), warningsConfigForProject(nullptr), includeDir, {}); const CppEditor::UsePrecompiledHeaders usePch - = CppEditor::CppCodeModelSettings::instance().usePrecompiledHeaders(); + = CppEditor::CppCodeModelSettings::usePrecompiledHeaders(nullptr); const QJsonArray projectPartOptions = fullProjectPartOptions( optionsBuilder, globalClangOptions()); const QJsonArray clangOptions = clangOptionsForFile({}, optionsBuilder.projectPart(), @@ -600,7 +600,7 @@ void ClangdClient::findUsages(const CppEditor::CursorInEditor &cursor, } } - const bool categorize = CppEditor::CppCodeModelSettings::instance().categorizeFindReferences(); + const bool categorize = CppEditor::CppCodeModelSettings::categorizeFindReferences(); // If it's a "normal" symbol, go right ahead. if (searchTerm != "operator" && Utils::allOf(searchTerm, [](const QChar &c) { @@ -920,9 +920,11 @@ void ClangdClient::updateParserConfig(const Utils::FilePath &filePath, CppEditor::ProjectFile::classify(filePath.toString())); const QJsonArray projectPartOptions = fullProjectPartOptions( optionsBuilder, globalClangOptions()); + const auto cppSettings = CppEditor::CppCodeModelSettings::settingsForProject( + projectPart->topLevelProject); addToCompilationDb(cdbChanges, *projectPart, - CppEditor::CppCodeModelSettings::instance().usePrecompiledHeaders(), + cppSettings.usePrecompiledHeaders(), projectPartOptions, filePath.parentDir(), file, diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index a718a9ed96..5e7f454d5e 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -166,7 +166,6 @@ GenerateCompilationDbResult generateCompilationDB(QList<ProjectInfo::ConstPtr> p } compileCommandsFile.write("["); - const UsePrecompiledHeaders usePch = CppCodeModelSettings::instance().usePrecompiledHeaders(); const QJsonArray jsonProjectOptions = QJsonArray::fromStringList(projectOptions); for (const ProjectInfo::ConstPtr &projectInfo : std::as_const(projectInfoList)) { QTC_ASSERT(projectInfo, continue); @@ -183,9 +182,15 @@ GenerateCompilationDbResult generateCompilationDB(QList<ProjectInfo::ConstPtr> p jsonProjectOptions); } for (const ProjectFile &projFile : projectPart->files) { - const QJsonObject json = createFileObject(baseDir, args, *projectPart, projFile, - purpose, ppOptions, usePch, - optionsBuilder.isClStyle()); + const QJsonObject json + = createFileObject(baseDir, + args, + *projectPart, + projFile, + purpose, + ppOptions, + projectInfo->settings().usePrecompiledHeaders(), + optionsBuilder.isClStyle()); if (compileCommandsFile.size() > 1) compileCommandsFile.write(","); compileCommandsFile.write(QJsonDocument(json).toJson(QJsonDocument::Compact)); diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 88a3176a6b..ae92afb45f 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -249,7 +249,7 @@ private: void ClangdTestFindReferences::initTestCase() { ClangdTest::initTestCase(); - CppEditor::CppCodeModelSettings::instance().setCategorizeFindReferences(true); + CppEditor::CppCodeModelSettings::setCategorizeFindReferences(true); connect(client(), &ClangdClient::foundReferences, this, [this](const SearchResultItems &results) { if (results.isEmpty()) diff --git a/src/plugins/clangtools/clangfileinfo.h b/src/plugins/clangtools/clangfileinfo.h index e9a7151160..deb53f6058 100644 --- a/src/plugins/clangtools/clangfileinfo.h +++ b/src/plugins/clangtools/clangfileinfo.h @@ -3,6 +3,7 @@ #pragma once +#include <cppeditor/cppcodemodelsettings.h> #include <cppeditor/cppprojectfile.h> #include <cppeditor/projectpart.h> @@ -19,9 +20,11 @@ public: FileInfo() = default; FileInfo(Utils::FilePath file, CppEditor::ProjectFile::Kind kind, + const CppEditor::CppCodeModelSettings &settings, CppEditor::ProjectPart::ConstPtr projectPart) : file(std::move(file)) , kind(kind) + , settings(settings.data()) , projectPart(projectPart) {} @@ -31,6 +34,7 @@ public: Utils::FilePath file; CppEditor::ProjectFile::Kind kind; + CppEditor::CppCodeModelSettings::Data settings; CppEditor::ProjectPart::ConstPtr projectPart; }; using FileInfos = std::vector<FileInfo>; diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 15635fc251..b7108a4389 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -341,7 +341,8 @@ private: QMap<FilePath, RefactoringFileInfo> m_refactoringFileInfos; }; -static FileInfos sortedFileInfos(const QVector<ProjectPart::ConstPtr> &projectParts) +static FileInfos sortedFileInfos(const CppCodeModelSettings &settings, + const QVector<ProjectPart::ConstPtr> &projectParts) { FileInfos fileInfos; @@ -359,7 +360,7 @@ static FileInfos sortedFileInfos(const QVector<ProjectPart::ConstPtr> &projectPa if (file.active && (ProjectFile::isSource(file.kind) || ProjectFile::isHeader(file.kind))) { ProjectFile::Kind sourceKind = ProjectFile::sourceKind(file.kind); - fileInfos.emplace_back(file.path, sourceKind, projectPart); + fileInfos.emplace_back(file.path, sourceKind, settings, projectPart); } } } @@ -901,7 +902,8 @@ FileInfos ClangTool::collectFileInfos(Project *project, FileSelection fileSelect const auto projectInfo = CppModelManager::projectInfo(project); QTC_ASSERT(projectInfo, return FileInfos()); - const FileInfos allFileInfos = sortedFileInfos(projectInfo->projectParts()); + const FileInfos allFileInfos = sortedFileInfos(projectInfo->settings(), + projectInfo->projectParts()); if (selectionType && *selectionType == FileSelectionType::AllFiles) return allFileInfos; diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index 13fdfba742..af3539b2ac 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -51,7 +51,7 @@ AnalyzeUnit::AnalyzeUnit(const FileInfo &fileInfo, arguments = extraClangToolsPrependOptions(); arguments.append( optionsBuilder.build(fileInfo.kind, - CppEditor::CppCodeModelSettings::instance().usePrecompiledHeaders())); + CppCodeModelSettings(fileInfo.settings).usePrecompiledHeaders())); arguments.append(extraClangToolsAppendOptions()); } diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp index d503f80d63..1e3055cb48 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.cpp +++ b/src/plugins/clangtools/documentclangtoolrunner.cpp @@ -132,10 +132,12 @@ static FileInfo getFileInfo(const FilePath &file, Project *project) // found the best candidate, early return ProjectFile::Kind sourceKind = ProjectFile::sourceKind(projectFile.kind); if (projectPart->buildTargetType != BuildTargetType::Unknown) - return FileInfo(projectFile.path, sourceKind, projectPart); + return FileInfo(projectFile.path, sourceKind, projectInfo->settings(), projectPart); // found something but keep looking for better candidates - if (candidate.projectPart.isNull()) - candidate = FileInfo(projectFile.path, sourceKind, projectPart); + if (candidate.projectPart.isNull()) { + candidate + = FileInfo(projectFile.path, sourceKind, projectInfo->settings(), projectPart); + } } } diff --git a/src/plugins/cppeditor/baseeditordocumentprocessor.cpp b/src/plugins/cppeditor/baseeditordocumentprocessor.cpp index d377a25337..786999223e 100644 --- a/src/plugins/cppeditor/baseeditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/baseeditordocumentprocessor.cpp @@ -27,7 +27,8 @@ namespace CppEditor { BaseEditorDocumentProcessor::BaseEditorDocumentProcessor(QTextDocument *textDocument, const Utils::FilePath &filePath) : m_filePath(filePath), - m_textDocument(textDocument) + m_textDocument(textDocument), + m_settings(CppCodeModelSettings::settingsForFile(filePath)) { } @@ -35,9 +36,11 @@ BaseEditorDocumentProcessor::~BaseEditorDocumentProcessor() = default; void BaseEditorDocumentProcessor::run(bool projectsUpdated) { + if (projectsUpdated) + m_settings.setData(CppCodeModelSettings::settingsForFile(m_filePath).data()); + const Utils::Language languagePreference - = CppCodeModelSettings::instance().interpretAmbigiousHeadersAsC() ? Utils::Language::C - : Utils::Language::Cxx; + = m_settings.interpretAmbigiousHeadersAsC() ? Utils::Language::C : Utils::Language::Cxx; runImpl({CppModelManager::workingCopy(), ProjectExplorer::ProjectManager::startupProject(), diff --git a/src/plugins/cppeditor/baseeditordocumentprocessor.h b/src/plugins/cppeditor/baseeditordocumentprocessor.h index 78c0f55aab..c825dc7a84 100644 --- a/src/plugins/cppeditor/baseeditordocumentprocessor.h +++ b/src/plugins/cppeditor/baseeditordocumentprocessor.h @@ -4,6 +4,7 @@ #pragma once #include "baseeditordocumentparser.h" +#include "cppcodemodelsettings.h" #include "cppcursorinfo.h" #include "cppeditor_global.h" #include "cppsemanticinfo.h" @@ -72,6 +73,7 @@ public: virtual QFuture<CursorInfo> cursorInfo(const CursorInfoParams ¶ms) = 0; const Utils::FilePath &filePath() const { return m_filePath; } + const CppCodeModelSettings &settings() const { return m_settings; } signals: // Signal interface to implement @@ -102,6 +104,7 @@ private: private: Utils::FilePath m_filePath; QTextDocument *m_textDocument; + CppCodeModelSettings m_settings; }; } // namespace CppEditor diff --git a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp index bd820c9222..5f827c74ce 100644 --- a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp @@ -144,16 +144,14 @@ QList<TextEditor::BlockRange> toTextEditorBlocks( BuiltinEditorDocumentProcessor::BuiltinEditorDocumentProcessor(TextEditor::TextDocument *document) : BaseEditorDocumentProcessor(document->document(), document->filePath()) , m_parser(new BuiltinEditorDocumentParser(document->filePath(), - CppCodeModelSettings::instance() - .effectiveIndexerFileSizeLimitInMb())) + settings().effectiveIndexerFileSizeLimitInMb())) , m_codeWarningsUpdated(false) , m_semanticHighlighter(new SemanticHighlighter(document)) { using namespace Internal; BaseEditorDocumentParser::Configuration config = m_parser->configuration(); - config.usePrecompiledHeaders = CppCodeModelSettings::instance().pchUsage() - != CppCodeModelSettings::PchUse_None; + config.usePrecompiledHeaders = settings().pchUsage() != CppCodeModelSettings::PchUse_None; m_parser->setConfiguration(config); m_semanticHighlighter->setHighlightingRunner( diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 8a28fcf691..5c8e3caff1 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -13,6 +13,7 @@ #include <coreplugin/session.h> #include <projectexplorer/project.h> +#include <projectexplorer/projectmanager.h> #include <utils/algorithm.h> #include <utils/hostosinfo.h> @@ -28,6 +29,7 @@ #include <QSettings> #include <QStandardPaths> +using namespace ProjectExplorer; using namespace Utils; namespace CppEditor { @@ -56,7 +58,7 @@ static Key clangdThreadLimitKey() { return "ClangdThreadLimit"; } static Key clangdDocumentThresholdKey() { return "ClangdDocumentThreshold"; } static Key clangdSizeThresholdEnabledKey() { return "ClangdSizeThresholdEnabled"; } static Key clangdSizeThresholdKey() { return "ClangdSizeThreshold"; } -static Key clangdUseGlobalSettingsKey() { return "useGlobalSettings"; } +static Key useGlobalSettingsKey() { return "useGlobalSettings"; } static Key clangdblockIndexingSettingsKey() { return "blockIndexing"; } static Key sessionsWithOneClangdKey() { return "SessionsWithOneClangd"; } static Key diagnosticConfigIdKey() { return "diagnosticConfigId"; } @@ -116,48 +118,118 @@ void CppCodeModelSettings::Data::fromMap(const Utils::Store &store) void CppCodeModelSettings::fromSettings(QtcSettings *s) { m_data.fromMap(storeFromSettings(Constants::CPPEDITOR_SETTINGSGROUP, s)); - emit changed(); } void CppCodeModelSettings::toSettings(QtcSettings *s) { - const Data def; - storeToSettingsWithDefault(Constants::CPPEDITOR_SETTINGSGROUP, s, m_data.toMap(), def.toMap()); - emit changed(); // TODO: Why? + storeToSettingsWithDefault(Constants::CPPEDITOR_SETTINGSGROUP, s, m_data.toMap(), Data().toMap()); } -CppCodeModelSettings &CppCodeModelSettings::instance() +CppCodeModelSettings &CppCodeModelSettings::globalInstance() { static CppCodeModelSettings theCppCodeModelSettings(Core::ICore::settings()); return theCppCodeModelSettings; } -void CppCodeModelSettings::setData(const Data &data) +CppCodeModelSettings CppCodeModelSettings::settingsForProject(const ProjectExplorer::Project *project) { - if (m_data != data) { - m_data = data; - toSettings(Core::ICore::settings()); - emit changed(); - } + return {CppCodeModelProjectSettings(const_cast<ProjectExplorer::Project *>(project)).data()}; +} + +CppCodeModelSettings CppCodeModelSettings::settingsForProject(const Utils::FilePath &projectFile) +{ + return settingsForProject(ProjectManager::projectWithProjectFilePath(projectFile)); +} + +CppCodeModelSettings CppCodeModelSettings::settingsForFile(const Utils::FilePath &file) +{ + return settingsForProject(ProjectManager::projectForFile(file)); +} + +void CppCodeModelSettings::setGlobalData(const Data &data) +{ + if (globalInstance().m_data == data) + return; + + globalInstance().m_data = data; + globalInstance().toSettings(Core::ICore::settings()); + emit globalInstance().changed(nullptr); +} + +CppCodeModelSettings::PCHUsage CppCodeModelSettings::pchUsage(const Project *project) +{ + return CppCodeModelSettings::settingsForProject(project).pchUsage(); } UsePrecompiledHeaders CppCodeModelSettings::usePrecompiledHeaders() const { - if (instance().pchUsage() == CppCodeModelSettings::PchUse_None) - return UsePrecompiledHeaders::No; - return UsePrecompiledHeaders::Yes; + return pchUsage() == CppCodeModelSettings::PchUse_None ? UsePrecompiledHeaders::No + : UsePrecompiledHeaders::Yes; +} + +UsePrecompiledHeaders CppCodeModelSettings::usePrecompiledHeaders(const Project *project) +{ + return CppCodeModelSettings::settingsForProject(project).usePrecompiledHeaders(); } int CppCodeModelSettings::effectiveIndexerFileSizeLimitInMb() const { - return instance().skipIndexingBigFiles() ? instance().indexerFileSizeLimitInMb() : -1; + return skipIndexingBigFiles() ? indexerFileSizeLimitInMb() : -1; +} + +bool CppCodeModelSettings::categorizeFindReferences() +{ + return globalInstance().m_data.categorizeFindReferences; } void CppCodeModelSettings::setCategorizeFindReferences(bool categorize) { - Data d = data(); + Data d = globalInstance().data(); d.categorizeFindReferences = categorize; - setData(d); + globalInstance().setGlobalData(d); +} + +CppCodeModelProjectSettings::CppCodeModelProjectSettings(ProjectExplorer::Project *project) + : m_project(project) +{ + loadSettings(); +} + +CppCodeModelSettings::Data CppCodeModelProjectSettings::data() const +{ + return m_useGlobalSettings ? CppCodeModelSettings::globalInstance().data() : m_customSettings; +} + +void CppCodeModelProjectSettings::setData(const CppCodeModelSettings::Data &data) +{ + m_customSettings = data; + saveSettings(); + emit CppCodeModelSettings::globalInstance().changed(m_project); +} + +void CppCodeModelProjectSettings::setUseGlobalSettings(bool useGlobal) +{ + m_useGlobalSettings = useGlobal; + saveSettings(); + emit CppCodeModelSettings::globalInstance().changed(m_project); +} + +void CppCodeModelProjectSettings::loadSettings() +{ + if (!m_project) + return; + const Store data = storeFromVariant(m_project->namedSettings(Constants::CPPEDITOR_SETTINGSGROUP)); + m_useGlobalSettings = data.value(useGlobalSettingsKey(), true).toBool(); + m_customSettings.fromMap(data); +} + +void CppCodeModelProjectSettings::saveSettings() +{ + if (!m_project) + return; + Store data = m_customSettings.toMap(); + data.insert(useGlobalSettingsKey(), m_useGlobalSettings); + m_project->setNamedSettings(Constants::CPPEDITOR_SETTINGSGROUP, variantFromStore(data)); } QString ClangdSettings::priorityToString(const IndexingPriority &priority) @@ -513,7 +585,7 @@ void ClangdProjectSettings::loadSettings() if (!m_project) return; const Store data = storeFromVariant(m_project->namedSettings(clangdSettingsKey())); - m_useGlobalSettings = data.value(clangdUseGlobalSettingsKey(), true).toBool(); + m_useGlobalSettings = data.value(useGlobalSettingsKey(), true).toBool(); m_blockIndexing = data.value(clangdblockIndexingSettingsKey(), false).toBool(); if (!m_useGlobalSettings) m_customSettings.fromMap(data); @@ -526,7 +598,7 @@ void ClangdProjectSettings::saveSettings() Store data; if (!m_useGlobalSettings) data = m_customSettings.toMap(); - data.insert(clangdUseGlobalSettingsKey(), m_useGlobalSettings); + data.insert(useGlobalSettingsKey(), m_useGlobalSettings); data.insert(clangdblockIndexingSettingsKey(), m_blockIndexing); m_project->setNamedSettings(clangdSettingsKey(), variantFromStore(data)); } diff --git a/src/plugins/cppeditor/cppcodemodelsettings.h b/src/plugins/cppeditor/cppcodemodelsettings.h index c76f3318f2..19cc078b26 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.h +++ b/src/plugins/cppeditor/cppcodemodelsettings.h @@ -37,6 +37,8 @@ public: class Data { public: + Data() = default; + Data(const Utils::Store &store) { fromMap(store); } Utils::Store toMap() const; void fromMap(const Utils::Store &store); @@ -53,26 +55,35 @@ public: QString ignorePattern; }; - static CppCodeModelSettings &instance(); + CppCodeModelSettings(const Data &data) : m_data(data) {} - void setData(const Data &data); + static CppCodeModelSettings &globalInstance(); // TODO: Make inaccessible. + static CppCodeModelSettings settingsForProject(const ProjectExplorer::Project *project); + static CppCodeModelSettings settingsForProject(const Utils::FilePath &projectFile); + static CppCodeModelSettings settingsForFile(const Utils::FilePath &file); + + static void setGlobalData(const Data &data); // TODO: Make inaccessible. + void setData(const Data &data) { m_data = data; } Data data() const { return m_data; } PCHUsage pchUsage() const { return m_data.pchUsage; } + static PCHUsage pchUsage(const ProjectExplorer::Project *project); UsePrecompiledHeaders usePrecompiledHeaders() const; + static UsePrecompiledHeaders usePrecompiledHeaders(const ProjectExplorer::Project *project); + bool interpretAmbigiousHeadersAsC() const { return m_data.interpretAmbigiousHeadersAsC; } bool skipIndexingBigFiles() const { return m_data.skipIndexingBigFiles; } bool useBuiltinPreprocessor() const { return m_data.useBuiltinPreprocessor; } int indexerFileSizeLimitInMb() const { return m_data.indexerFileSizeLimitInMb; } int effectiveIndexerFileSizeLimitInMb() const; - bool categorizeFindReferences() const { return m_data.categorizeFindReferences; } bool ignoreFiles() const { return m_data.ignoreFiles; } QString ignorePattern() const { return m_data.ignorePattern; } - void setCategorizeFindReferences(bool categorize); + static bool categorizeFindReferences(); + static void setCategorizeFindReferences(bool categorize); signals: - void changed(); + void changed(ProjectExplorer::Project *project); private: CppCodeModelSettings() = default; @@ -84,6 +95,25 @@ private: Data m_data; }; +class CppCodeModelProjectSettings +{ +public: + CppCodeModelProjectSettings(ProjectExplorer::Project *project); + + CppCodeModelSettings::Data data() const; + void setData(const CppCodeModelSettings::Data &data); + bool useGlobalSettings() const { return m_useGlobalSettings; } + void setUseGlobalSettings(bool useGlobal); + +private: + void loadSettings(); + void saveSettings(); + + ProjectExplorer::Project * const m_project; + CppCodeModelSettings::Data m_customSettings; + bool m_useGlobalSettings = true; +}; + class CPPEDITOR_EXPORT ClangdSettings : public QObject { Q_OBJECT diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp index bb91165705..616bb34f61 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp @@ -50,14 +50,18 @@ namespace CppEditor::Internal { class CppCodeModelSettingsWidget final : public Core::IOptionsPageWidget { + Q_OBJECT public: CppCodeModelSettingsWidget(const CppCodeModelSettings::Data &data); -private: - void apply() final { CppCodeModelSettings::instance().setData(data()); } - CppCodeModelSettings::Data data() const; +signals: + void settingsDataChanged(); + +private: + void apply() final { CppCodeModelSettings::globalInstance().setGlobalData(data()); } + QCheckBox *m_interpretAmbiguousHeadersAsCHeaders; QCheckBox *m_ignorePchCheckBox; QCheckBox *m_useBuiltinPreprocessorCheckBox; @@ -126,6 +130,23 @@ CppCodeModelSettingsWidget::CppCodeModelSettingsWidget(const CppCodeModelSetting }, st }.attachTo(this); + + for (const QCheckBox *const b : {m_interpretAmbiguousHeadersAsCHeaders, + m_ignorePchCheckBox, + m_useBuiltinPreprocessorCheckBox, + m_skipIndexingBigFilesCheckBox, + m_ignoreFilesCheckBox}) { + connect(b, &QCheckBox::toggled, this, &CppCodeModelSettingsWidget::settingsDataChanged); + } + connect(m_bigFilesLimitSpinBox, &QSpinBox::valueChanged, + this, &CppCodeModelSettingsWidget::settingsDataChanged); + + const auto timer = new QTimer(this); + timer->setSingleShot(true); + timer->setInterval(1000); + connect(timer, &QTimer::timeout, this, &CppCodeModelSettingsWidget::settingsDataChanged); + connect(m_ignorePatternTextEdit, &QPlainTextEdit::textChanged, + timer, qOverload<>(&QTimer::start)); } CppCodeModelSettings::Data CppCodeModelSettingsWidget::data() const @@ -153,15 +174,62 @@ public: setDisplayCategory(Tr::tr("C++")); setCategoryIconPath(":/projectexplorer/images/settingscategory_cpp.png"); setWidgetCreator( - [] { return new CppCodeModelSettingsWidget(CppCodeModelSettings::instance().data()); }); + [] { return new CppCodeModelSettingsWidget(CppCodeModelSettings::globalInstance().data()); }); } }; -void setupCppCodeModelSettings() +void setupCppCodeModelSettingsPage() { static CppCodeModelSettingsPage theCppCodeModelSettingsPage; } +class CppCodeModelProjectSettingsWidget : public ProjectSettingsWidget +{ +public: + CppCodeModelProjectSettingsWidget(const CppCodeModelProjectSettings &settings) + : m_settings(settings), m_widget(settings.data()) + { + setGlobalSettingsId(Constants::CPP_CODE_MODEL_SETTINGS_ID); + const auto layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(&m_widget); + + setUseGlobalSettings(m_settings.useGlobalSettings()); + m_widget.setEnabled(!useGlobalSettings()); + connect(this, &ProjectSettingsWidget::useGlobalSettingsChanged, this, + [this](bool checked) { + m_widget.setEnabled(!checked); + m_settings.setUseGlobalSettings(checked); + if (!checked) + m_settings.setData(m_widget.data()); + }); + + connect(&m_widget, &CppCodeModelSettingsWidget::settingsDataChanged, + this, [this] { m_settings.setData(m_widget.data()); }); + } + +private: + CppCodeModelProjectSettings m_settings; + CppCodeModelSettingsWidget m_widget; +}; + +class CppCodeModelProjectSettingsPanelFactory final : public ProjectPanelFactory +{ +public: + CppCodeModelProjectSettingsPanelFactory() + { + setPriority(100); + setDisplayName(Tr::tr("C++ Code Model")); + setCreateWidgetFunction([](Project *project) { + return new CppCodeModelProjectSettingsWidget(project); + }); + } +}; +void setupCppCodeModelProjectSettingsPanel() +{ + static CppCodeModelProjectSettingsPanelFactory factory; +} + class ClangdSettingsWidget final : public QWidget { Q_OBJECT diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.h b/src/plugins/cppeditor/cppcodemodelsettingspage.h index 35a6bc5111..4c11b6251e 100644 --- a/src/plugins/cppeditor/cppcodemodelsettingspage.h +++ b/src/plugins/cppeditor/cppcodemodelsettingspage.h @@ -5,7 +5,8 @@ namespace CppEditor::Internal { -void setupCppCodeModelSettings(); +void setupCppCodeModelSettingsPage(); +void setupCppCodeModelProjectSettingsPanel(); void setupClangdProjectSettingsPanel(); void setupClangdSettingsPage(); diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index a98a76ec42..4328c93970 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -70,6 +70,7 @@ #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectmanager.h> #include <projectexplorer/projecttree.h> +#include <projectexplorer/rawprojectpart.h> #include <texteditor/colorpreviewhoverhandler.h> #include <texteditor/snippets/snippetprovider.h> @@ -202,7 +203,10 @@ void CppEditorPlugin::initialize() d = new CppEditorPluginPrivate; setupCppQuickFixSettings(); - setupCppCodeModelSettings(); + setupCppCodeModelSettingsPage(); + provideCppSettingsRetriever([](const Project *p) { + return CppCodeModelSettings::settingsForProject(p).data().toMap(); + }); setupCppOutline(); setupCppCodeStyleSettings(); setupCppProjectUpdater(); @@ -227,6 +231,7 @@ void CppEditorPlugin::extensionsInitialized() { setupCppQuickFixProjectPanel(); setupCppFileSettings(); + setupCppCodeModelProjectSettingsPanel(); if (CppModelManager::isClangCodeModelActive()) { setupClangdProjectSettingsPanel(); @@ -349,9 +354,9 @@ void CppEditorPlugin::addPerSymbolActions() findRefsCategorized.addToContainers(menus, Constants::G_SYMBOL); findRefsCategorized.addOnTriggered(this, [] { if (const auto w = currentCppEditorWidget()) { - CppCodeModelSettings::instance().setCategorizeFindReferences(true); + CppCodeModelSettings::setCategorizeFindReferences(true); w->findUsages(); - CppCodeModelSettings::instance().setCategorizeFindReferences(false); + CppCodeModelSettings::setCategorizeFindReferences(false); } }); diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index 683eda587a..35c9400e9a 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -388,7 +388,7 @@ void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, search->setTextToReplace(replacement); if (callback) search->makeNonInteractive(callback); - if (CppCodeModelSettings::instance().categorizeFindReferences()) + if (CppCodeModelSettings::categorizeFindReferences()) search->setFilter(new CppSearchResultFilter); setupSearch(search); search->setSearchAgainSupported(true); @@ -397,7 +397,7 @@ void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, CppFindReferencesParameters parameters; parameters.symbolId = fullIdForSymbol(symbol); parameters.symbolFilePath = symbol->filePath(); - parameters.categorize = CppCodeModelSettings::instance().categorizeFindReferences(); + parameters.categorize = CppCodeModelSettings::categorizeFindReferences(); parameters.preferLowerCaseFileNames = preferLowerCaseFileNames( ProjectManager::projectForFile(symbol->filePath())); @@ -408,8 +408,7 @@ void CppFindReferences::findUsages(CPlusPlus::Symbol *symbol, } search->setUserData(QVariant::fromValue(parameters)); - findAll_helper(search, symbol, context, - CppCodeModelSettings::instance().categorizeFindReferences()); + findAll_helper(search, symbol, context, CppCodeModelSettings::categorizeFindReferences()); } void CppFindReferences::renameUsages(CPlusPlus::Symbol *symbol, diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 6e81e86f0c..5ea954add4 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -407,7 +407,7 @@ void CppModelManager::showPreprocessedFile(bool inNextSplit) saveAndOpen(outFilePath, content.append(preprocessedDoc->utf8Source()), inNextSplit); }; - if (CppCodeModelSettings::instance().useBuiltinPreprocessor()) { + if (CppCodeModelSettings::settingsForFile(filePath).useBuiltinPreprocessor()) { useBuiltinPreprocessor(); return; } @@ -1023,6 +1023,9 @@ CppModelManager::CppModelManager() connect(ICore::instance(), &ICore::coreAboutToClose, this, &CppModelManager::onCoreAboutToClose); + connect(&CppCodeModelSettings::globalInstance(), &CppCodeModelSettings::changed, + this, &CppModelManager::onSettingsChange); + d->m_fallbackProjectPartTimer.setSingleShot(true); d->m_fallbackProjectPartTimer.setInterval(5000); connect(&d->m_fallbackProjectPartTimer, &QTimer::timeout, @@ -1349,12 +1352,17 @@ QFuture<void> CppModelManager::updateSourceFiles(const QSet<FilePath> &sourceFil if (sourceFiles.isEmpty() || !d->m_indexerEnabled) return QFuture<void>(); - const CppCodeModelSettings &settings = CppCodeModelSettings::instance(); - const QSet<QString> filteredFiles - = filteredFilesRemoved(transform(sourceFiles, &FilePath::toString), - settings.effectiveIndexerFileSizeLimitInMb(), - settings.ignoreFiles(), - settings.ignorePattern()); + QHash<Project *, QSet<QString>> sourcesPerProject; // TODO: Work with QList from here on? + for (const FilePath &fp : sourceFiles) + sourcesPerProject[ProjectManager::projectForFile(fp)] << fp.toString(); + QSet<QString> filteredFiles; + for (auto it = sourcesPerProject.cbegin(); it != sourcesPerProject.cend(); ++it) { + const CppCodeModelSettings settings = CppCodeModelSettings::settingsForProject(it.key()); + filteredFiles.unite(filteredFilesRemoved(it.value(), + settings.effectiveIndexerFileSizeLimitInMb(), + settings.ignoreFiles(), + settings.ignorePattern())); + } return d->m_internalIndexingSupport->refreshSourceFiles(filteredFiles, mode); } @@ -1992,6 +2000,21 @@ void CppModelManager::onCoreAboutToClose() d->m_enableGC = false; } +void CppModelManager::onSettingsChange(Project *project) +{ + ProjectInfoList info; + if (project) + info << projectInfo(project); + else + info << projectInfos(); + for (const ProjectInfo::ConstPtr &pi : std::as_const(info)) { + const CppCodeModelSettings newSettings = CppCodeModelSettings::settingsForProject( + pi->projectFilePath()); + if (pi->settings().data() != newSettings.data()) + updateProjectInfo(ProjectInfo::cloneWithNewSettings(pi, newSettings)); + } +} + void CppModelManager::setupFallbackProjectPart() { ToolchainInfo tcInfo; diff --git a/src/plugins/cppeditor/cppmodelmanager.h b/src/plugins/cppeditor/cppmodelmanager.h index 77cb212c6e..d1a558ce9c 100644 --- a/src/plugins/cppeditor/cppmodelmanager.h +++ b/src/plugins/cppeditor/cppmodelmanager.h @@ -288,6 +288,7 @@ private: static void onSourceFilesRefreshed(); static void onCurrentEditorChanged(Core::IEditor *editor); static void onCoreAboutToClose(); + static void onSettingsChange(ProjectExplorer::Project *project); static void setupFallbackProjectPart(); static void delayedGC(); diff --git a/src/plugins/cppeditor/cppmodelmanager_test.cpp b/src/plugins/cppeditor/cppmodelmanager_test.cpp index 9e72a224b9..a896563a61 100644 --- a/src/plugins/cppeditor/cppmodelmanager_test.cpp +++ b/src/plugins/cppeditor/cppmodelmanager_test.cpp @@ -19,6 +19,7 @@ #include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectmanager.h> +#include <projectexplorer/projectnodes.h> #include <utils/hostosinfo.h> #include <utils/qtcassert.h> @@ -1174,4 +1175,105 @@ void ModelManagerTest::testDocumentsAndRevisions() VERIFY_DOCUMENT_REVISION(CppModelManager::document(filePath2), 4U); } +void ModelManagerTest::testSettingsChanges() +{ + ModelManagerTestHelper helper; + + int refreshCount = 0; + QSet<QString> refreshedFiles; + connect(CppModelManager::instance(), &CppModelManager::sourceFilesRefreshed, + &helper, [&](const QSet<QString> &files) { + ++refreshCount; + refreshedFiles.unite(files); + }); + const auto waitForRefresh = [] { + return ::CppEditor::Tests::waitForSignalOrTimeout(CppModelManager::instance(), + &CppModelManager::sourceFilesRefreshed, + 5000); + }; + + const auto setupProjectNodes = [](Project &p, const ProjectFiles &projectFiles) { + auto rootNode = std::make_unique<ProjectNode>(p.projectFilePath()); + for (const ProjectFile &sourceFile : projectFiles) { + rootNode->addNestedNode(std::make_unique<FileNode>(sourceFile.path, + sourceFile.isHeader() + ? FileType::Header + : FileType::Source)); + } + p.setRootProjectNode(std::move(rootNode)); + }; + + // Set up projects. + const MyTestDataDir p1Dir("testdata_project1"); + const FilePaths p1Files + = Utils::transform({"baz.h", "baz2.h", "baz3.h", "foo.cpp", "foo.h", "main.cpp"}, + [&](const QString &fn) { return p1Dir.filePath(fn); }); + const ProjectFiles p1ProjectFiles = Utils::transform(p1Files, [](const FilePath &fp) { + return ProjectFile(fp, ProjectFile::classify(fp.toString())); + }); + Project * const p1 = helper.createProject("testdata_project1", FilePath::fromString("p1.pro")); + setupProjectNodes(*p1, p1ProjectFiles); + RawProjectPart rpp1; + const auto part1 = ProjectPart::create(p1->projectFilePath(), rpp1, {}, p1ProjectFiles); + const auto pi1 = ProjectInfo::create(ProjectUpdateInfo(p1, KitInfo(nullptr), {}, {}), {part1}); + const auto p1Sources = Utils::transform<QSet<QString>>(p1Files, &FilePath::toString); + CppModelManager::updateProjectInfo(pi1); + + const MyTestDataDir p2Dir("testdata_project2"); + const FilePaths p2Files + = Utils::transform({"bar.h", "bar.cpp", "foobar2000.h", "foobar4000.h", "main.cpp"}, + [&](const QString &fn) { return p1Dir.filePath(fn); }); + const ProjectFiles p2ProjectFiles = Utils::transform(p2Files, [](const FilePath &fp) { + return ProjectFile(fp, ProjectFile::classify(fp.toString())); + }); + Project * const p2 = helper.createProject("testdata_project2", FilePath::fromString("p2.pro")); + setupProjectNodes(*p2, p2ProjectFiles); + RawProjectPart rpp2; + const auto part2 = ProjectPart::create(p2->projectFilePath(), rpp2, {}, p2ProjectFiles); + const auto pi2 = ProjectInfo::create(ProjectUpdateInfo(p2, KitInfo(nullptr), {}, {}), {part2}); + const auto p2Sources = Utils::transform<QSet<QString>>(p2Files, &FilePath::toString); + CppModelManager::updateProjectInfo(pi2); + + // Initial check: Have all files been indexed? + while (refreshCount < 2) + QVERIFY(waitForRefresh()); + const auto allSources = p1Sources + p2Sources; + QCOMPARE(refreshedFiles, allSources); + + // Switch first project from global to local settings. Nothing should get re-indexed, + // as the default values are the same. + refreshCount = 0; + refreshedFiles.clear(); + CppCodeModelProjectSettings p1Settings(p1); + QVERIFY(p1Settings.useGlobalSettings()); + p1Settings.setUseGlobalSettings(false); + QCOMPARE(refreshCount, 0); + QVERIFY(!waitForRefresh()); + + // Change global settings. Only the second project should get re-indexed, as the first one + // has its own settings, which are still the same. + CppCodeModelSettings::Data globalSettings + = CppCodeModelSettings::settingsForProject(nullptr).data(); + globalSettings.indexerFileSizeLimitInMb = 1; + CppCodeModelSettings::setGlobalData(globalSettings); + if (refreshCount == 0) + QVERIFY(waitForRefresh()); + QVERIFY(!waitForRefresh()); + QCOMPARE(refreshedFiles, p2Sources); + + // Change first project's settings. Only this project should get re-indexed. + refreshCount = 0; + refreshedFiles.clear(); + CppCodeModelSettings::Data p1Data = p1Settings.data(); + p1Data.ignoreFiles = true; + p1Data.ignorePattern = "baz3.h"; + p1Settings.setData(p1Data); + if (refreshCount == 0) + QVERIFY(waitForRefresh()); + QVERIFY(!waitForRefresh()); + QSet<QString> filteredP1Sources = p1Sources; + filteredP1Sources -= p1Dir.filePath("baz3.h").toString(); + QCOMPARE(refreshedFiles, filteredP1Sources); +} + } // CppEditor::Internal diff --git a/src/plugins/cppeditor/cppmodelmanager_test.h b/src/plugins/cppeditor/cppmodelmanager_test.h index 939c0f4cca..26cbefd1c8 100644 --- a/src/plugins/cppeditor/cppmodelmanager_test.h +++ b/src/plugins/cppeditor/cppmodelmanager_test.h @@ -31,6 +31,7 @@ private slots: void testRenameIncludes(); void testRenameIncludesInEditor(); void testDocumentsAndRevisions(); + void testSettingsChanges(); }; } // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/projectinfo.cpp b/src/plugins/cppeditor/projectinfo.cpp index 57466d1cd9..8a393df6d3 100644 --- a/src/plugins/cppeditor/projectinfo.cpp +++ b/src/plugins/cppeditor/projectinfo.cpp @@ -19,6 +19,12 @@ ProjectInfo::ConstPtr ProjectInfo::create(const ProjectExplorer::ProjectUpdateIn return ConstPtr(new ProjectInfo(updateInfo, projectParts)); } +ProjectInfo::ConstPtr ProjectInfo::cloneWithNewSettings(const ConstPtr &pi, + const CppCodeModelSettings &settings) +{ + return ConstPtr(new ProjectInfo(pi, settings)); +} + bool ProjectInfo::operator ==(const ProjectInfo &other) const { return m_projectName == other.m_projectName @@ -27,6 +33,7 @@ bool ProjectInfo::operator ==(const ProjectInfo &other) const && m_projectParts == other.m_projectParts && m_headerPaths == other.m_headerPaths && m_sourceFiles == other.m_sourceFiles + && m_settings.data() == other.m_settings.data() && m_defines == other.m_defines; } @@ -42,7 +49,8 @@ bool ProjectInfo::definesChanged(const ProjectInfo &other) const bool ProjectInfo::configurationChanged(const ProjectInfo &other) const { - return definesChanged(other) || m_headerPaths != other.m_headerPaths; + return definesChanged(other) || m_headerPaths != other.m_headerPaths + || m_settings.data() != other.settings().data(); } bool ProjectInfo::configurationOrFilesChanged(const ProjectInfo &other) const @@ -89,7 +97,20 @@ ProjectInfo::ProjectInfo(const ProjectExplorer::ProjectUpdateInfo &updateInfo, m_buildRoot(updateInfo.buildRoot), m_headerPaths(getHeaderPaths(projectParts)), m_sourceFiles(getSourceFiles(projectParts)), - m_defines(getDefines(projectParts)) + m_defines(getDefines(projectParts)), + m_settings(CppCodeModelSettings::Data(updateInfo.cppSettings)) +{ +} + +ProjectInfo::ProjectInfo(const ConstPtr &pi, const CppCodeModelSettings &settings) + : m_projectParts(pi->projectParts()), + m_projectName(pi->projectName()), + m_projectFilePath(pi->projectFilePath()), + m_buildRoot(pi->buildRoot()), + m_headerPaths(pi->m_headerPaths), + m_sourceFiles(pi->sourceFiles()), + m_defines(pi->m_defines), + m_settings(settings.data()) { } diff --git a/src/plugins/cppeditor/projectinfo.h b/src/plugins/cppeditor/projectinfo.h index 26f92eb6a7..3b18c7ae6f 100644 --- a/src/plugins/cppeditor/projectinfo.h +++ b/src/plugins/cppeditor/projectinfo.h @@ -5,6 +5,7 @@ #include "cppeditor_global.h" +#include "cppcodemodelsettings.h" #include "projectpart.h" #include <projectexplorer/project.h> @@ -28,6 +29,8 @@ public: using ConstPtr = std::shared_ptr<const ProjectInfo>; static ConstPtr create(const ProjectExplorer::ProjectUpdateInfo &updateInfo, const QVector<ProjectPart::ConstPtr> &projectParts); + static ConstPtr cloneWithNewSettings(const ProjectInfo::ConstPtr &pi, + const CppCodeModelSettings &settings); const QVector<ProjectPart::ConstPtr> &projectParts() const { return m_projectParts; } const QSet<Utils::FilePath> &sourceFiles() const { return m_sourceFiles; } @@ -35,6 +38,7 @@ public: Utils::FilePath projectFilePath() const { return m_projectFilePath; } Utils::FilePath projectRoot() const { return m_projectFilePath.parentDir(); } Utils::FilePath buildRoot() const { return m_buildRoot; } + const CppCodeModelSettings &settings() const { return m_settings; } // Comparisons bool operator ==(const ProjectInfo &other) const; @@ -46,6 +50,7 @@ public: private: ProjectInfo(const ProjectExplorer::ProjectUpdateInfo &updateInfo, const QVector<ProjectPart::ConstPtr> &projectParts); + ProjectInfo(const ProjectInfo::ConstPtr &pi, const CppCodeModelSettings &settings); const QVector<ProjectPart::ConstPtr> m_projectParts; const QString m_projectName; @@ -54,6 +59,7 @@ private: const ProjectExplorer::HeaderPaths m_headerPaths; const QSet<Utils::FilePath> m_sourceFiles; const ProjectExplorer::Macros m_defines; + const CppCodeModelSettings m_settings; }; using ProjectInfoList = QList<ProjectInfo::ConstPtr>; diff --git a/src/plugins/projectexplorer/rawprojectpart.cpp b/src/plugins/projectexplorer/rawprojectpart.cpp index 3f525ea095..9bb69c5e84 100644 --- a/src/plugins/projectexplorer/rawprojectpart.cpp +++ b/src/plugins/projectexplorer/rawprojectpart.cpp @@ -178,6 +178,12 @@ ToolchainInfo::ToolchainInfo(const Toolchain *toolChain, } } +static CppSettingsRetriever g_cppSettingsRetriever; +void provideCppSettingsRetriever(const CppSettingsRetriever &retriever) +{ + g_cppSettingsRetriever = retriever; +} + ProjectUpdateInfo::ProjectUpdateInfo(Project *project, const KitInfo &kitInfo, const Utils::Environment &env, @@ -188,6 +194,8 @@ ProjectUpdateInfo::ProjectUpdateInfo(Project *project, , cToolchainInfo(ToolchainInfo(kitInfo.cToolchain, kitInfo.sysRootPath, env)) , cxxToolchainInfo(ToolchainInfo(kitInfo.cxxToolchain, kitInfo.sysRootPath, env)) { + if (g_cppSettingsRetriever) + cppSettings = g_cppSettingsRetriever(project); if (project) { projectName = project->displayName(); projectFilePath = project->projectFilePath(); diff --git a/src/plugins/projectexplorer/rawprojectpart.h b/src/plugins/projectexplorer/rawprojectpart.h index 75503170da..7ebe5eed1d 100644 --- a/src/plugins/projectexplorer/rawprojectpart.h +++ b/src/plugins/projectexplorer/rawprojectpart.h @@ -14,6 +14,7 @@ #include <utils/cpplanguage_details.h> #include <utils/environment.h> #include <utils/fileutils.h> +#include <utils/store.h> #include <QPointer> @@ -170,9 +171,13 @@ public: Utils::FilePath buildRoot; RawProjectParts rawProjectParts; RppGenerator rppGenerator; + Utils::Store cppSettings; ToolchainInfo cToolchainInfo; ToolchainInfo cxxToolchainInfo; }; +using CppSettingsRetriever = std::function<Utils::Store(const Project *)>; +void PROJECTEXPLORER_EXPORT provideCppSettingsRetriever(const CppSettingsRetriever &retriever); + } // namespace ProjectExplorer |