From 0b8df41387005156ea73b029f4d9d77f91ce5eb5 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 17 Jan 2017 15:27:31 +0100 Subject: [PATCH] CppTools: Provide hints about chosen project part for editor document Parse issues can have multiple reasons (invalid kit, not a project file, actual parse issue) and we should be able to tell them apart. With this change, we can distinguish between the fallback project part and a ambiguous project part. Follow up changes will use this to display more accurate diagnostics. Change-Id: Icc8767607cc17dc14d6227b07f34e81ba5525a96 Reviewed-by: David Schulz --- .../clangeditordocumentparser.cpp | 13 +- .../clangeditordocumentprocessor.cpp | 5 +- src/plugins/clangcodemodel/clangutils.cpp | 2 +- .../cppeditor/cppcodemodelinspectordialog.cpp | 2 +- src/plugins/cppeditor/cppeditordocument.cpp | 3 +- .../cpptools/baseeditordocumentparser.cpp | 29 ++-- .../cpptools/baseeditordocumentparser.h | 22 ++- .../cpptools/baseeditordocumentprocessor.cpp | 2 +- .../cpptools/baseeditordocumentprocessor.h | 3 +- .../cpptools/builtineditordocumentparser.cpp | 15 +- .../builtineditordocumentprocessor.cpp | 2 + src/plugins/cpptools/cppmodelmanager_test.cpp | 2 +- .../cpptools/cppprojectpartchooser.cpp | 160 ++++++++++++------ src/plugins/cpptools/cppprojectpartchooser.h | 17 +- src/plugins/cpptools/cpptools.pro | 2 +- src/plugins/cpptools/cpptools.qbs | 2 +- .../{cpplanguage.h => cpptools_utils.h} | 15 ++ .../cpptoolsbridgeqtcreatorimplementation.cpp | 2 +- .../unittest/cppprojectpartchooser-test.cpp | 53 ++++-- 19 files changed, 235 insertions(+), 116 deletions(-) rename src/plugins/cpptools/{cpplanguage.h => cpptools_utils.h} (86%) diff --git a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp index 33ec351b4c2..860b41b04de 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentparser.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentparser.cpp @@ -39,12 +39,13 @@ void ClangEditorDocumentParser::updateImpl(const QFutureInterface &, const UpdateParams &updateParams) { State state_ = state(); - state_.projectPart = determineProjectPart(filePath(), - configuration(), - state_, - updateParams.activeProject, - updateParams.languagePreference, - updateParams.hasActiveProjectChanged); + state_.projectPartInfo = determineProjectPart(filePath(), + configuration(), + state_, + updateParams.activeProject, + updateParams.languagePreference, + updateParams.hasActiveProjectChanged); + emit projectPartInfoUpdated(state_.projectPartInfo); setState(state_); } diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 9104d5d1165..05874085c08 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -80,6 +80,9 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor( connect(&m_updateTranslationUnitTimer, &QTimer::timeout, this, &ClangEditorDocumentProcessor::updateTranslationUnitIfProjectPartExists); + connect(m_parser.data(), &ClangEditorDocumentParser::projectPartInfoUpdated, + this, &BaseEditorDocumentProcessor::projectPartInfoUpdated); + // Forwarding the semantic info from the builtin processor enables us to provide all // editor (widget) related features that are not yet implemented by the clang plugin. connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::cppDocumentUpdated, @@ -302,7 +305,7 @@ static bool isProjectPartLoadedOrIsFallback(CppTools::ProjectPart::Ptr projectPa void ClangEditorDocumentProcessor::updateProjectPartAndTranslationUnitForEditor() { - const CppTools::ProjectPart::Ptr projectPart = m_parser->projectPart(); + const CppTools::ProjectPart::Ptr projectPart = m_parser->projectPartInfo().projectPart; if (isProjectPartLoadedOrIsFallback(projectPart)) { registerTranslationUnitForEditor(projectPart.data()); diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index b99f7a8fc20..4e26ef3b190 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -131,7 +131,7 @@ QStringList createClangOptions(const ProjectPart::Ptr &pPart, ProjectFile::Kind ProjectPart::Ptr projectPartForFile(const QString &filePath) { if (const auto parser = CppTools::BaseEditorDocumentParser::get(filePath)) - return parser->projectPart(); + return parser->projectPartInfo().projectPart; return ProjectPart::Ptr(); } diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp index 0dafea42d33..04d1560297a 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp @@ -1580,7 +1580,7 @@ void CppCodeModelInspectorDialog::refresh() // Project Parts const ProjectPart::Ptr editorsProjectPart = cppEditorDocument - ? cppEditorDocument->processor()->parser()->projectPart() + ? cppEditorDocument->processor()->parser()->projectPartInfo().projectPart : ProjectPart::Ptr(); const QList projectInfos = cmmi->projectInfos(); diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index 91918f9d3bd..6a28974ae27 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -274,7 +274,8 @@ void CppEditorDocument::setPreprocessorSettings(const CppTools::ProjectPart::Ptr { const auto parser = processor()->parser(); QTC_ASSERT(parser, return); - if (parser->projectPart() != projectPart || parser->configuration().editorDefines != defines) { + if (parser->projectPartInfo().projectPart != projectPart + || parser->configuration().editorDefines != defines) { CppTools::BaseEditorDocumentParser::Configuration config = parser->configuration(); config.manuallySetProjectPart = projectPart; config.editorDefines = defines; diff --git a/src/plugins/cpptools/baseeditordocumentparser.cpp b/src/plugins/cpptools/baseeditordocumentparser.cpp index ca4d16e5646..617c61de0ad 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.cpp +++ b/src/plugins/cpptools/baseeditordocumentparser.cpp @@ -54,6 +54,8 @@ namespace CppTools { BaseEditorDocumentParser::BaseEditorDocumentParser(const QString &filePath) : m_filePath(filePath) { + static int meta = qRegisterMetaType("CppTools::ProjectPartInfo"); + Q_UNUSED(meta); } BaseEditorDocumentParser::~BaseEditorDocumentParser() @@ -102,9 +104,9 @@ void BaseEditorDocumentParser::setState(const State &state) m_state = state; } -ProjectPart::Ptr BaseEditorDocumentParser::projectPart() const +ProjectPartInfo BaseEditorDocumentParser::projectPartInfo() const { - return state().projectPart; + return state().projectPartInfo; } BaseEditorDocumentParser::Ptr BaseEditorDocumentParser::get(const QString &filePath) @@ -117,7 +119,7 @@ BaseEditorDocumentParser::Ptr BaseEditorDocumentParser::get(const QString &fileP return BaseEditorDocumentParser::Ptr(); } -ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart( +ProjectPartInfo BaseEditorDocumentParser::determineProjectPart( const QString &filePath, const Configuration &config, const State &state, @@ -125,7 +127,9 @@ ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart( Language languagePreference, bool hasActiveProjectChanged) { - Internal::ProjectPartChooser chooser; + using Internal::ProjectPartChooser; + + ProjectPartChooser chooser; chooser.setFallbackProjectPart([](){ return CppModelManager::instance()->fallbackProjectPart(); }); @@ -137,13 +141,16 @@ ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart( return CppModelManager::instance()->projectPartFromDependencies(fileName); }); - return chooser.choose(filePath, - state.projectPart, - config.manuallySetProjectPart, - config.stickToPreviousProjectPart, - activeProject, - languagePreference, - hasActiveProjectChanged); + const ProjectPartInfo chooserResult + = chooser.choose(filePath, + state.projectPartInfo.projectPart, + config.manuallySetProjectPart, + config.stickToPreviousProjectPart, + activeProject, + languagePreference, + hasActiveProjectChanged); + + return chooserResult; } } // namespace CppTools diff --git a/src/plugins/cpptools/baseeditordocumentparser.h b/src/plugins/cpptools/baseeditordocumentparser.h index 92f919e96d9..1cf71fefc6b 100644 --- a/src/plugins/cpptools/baseeditordocumentparser.h +++ b/src/plugins/cpptools/baseeditordocumentparser.h @@ -25,8 +25,8 @@ #pragma once -#include "cpplanguage.h" #include "cpptools_global.h" +#include "cpptools_utils.h" #include "cppworkingcopy.h" #include "projectpart.h" @@ -82,22 +82,26 @@ public: void update(const UpdateParams &updateParams); void update(const QFutureInterface &future, const UpdateParams &updateParams); - ProjectPart::Ptr projectPart() const; + ProjectPartInfo projectPartInfo() const; + +signals: + void projectPartInfoUpdated(const CppTools::ProjectPartInfo &projectPartInfo); protected: struct State { QByteArray editorDefines; - ProjectPart::Ptr projectPart; + ProjectPartInfo projectPartInfo; }; State state() const; void setState(const State &state); - static ProjectPart::Ptr determineProjectPart(const QString &filePath, - const Configuration &config, - const State &state, - const ProjectExplorer::Project *activeProject, - Language languagePreference, - bool hasActiveProjectChanged); + static ProjectPartInfo determineProjectPart( + const QString &filePath, + const Configuration &config, + const State &state, + const ProjectExplorer::Project *activeProject, + Language languagePreference, + bool hasActiveProjectChanged); mutable QMutex m_stateAndConfigurationMutex; diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.cpp b/src/plugins/cpptools/baseeditordocumentprocessor.cpp index b656c5798a5..950d052793f 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.cpp +++ b/src/plugins/cpptools/baseeditordocumentprocessor.cpp @@ -26,10 +26,10 @@ #include "baseeditordocumentprocessor.h" #include "cppcodemodelsettings.h" -#include "cpplanguage.h" #include "cppmodelmanager.h" #include "cpptoolsbridge.h" #include "cpptoolsreuse.h" +#include "cpptools_utils.h" #include "editordocumenthandle.h" #include diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.h b/src/plugins/cpptools/baseeditordocumentprocessor.h index f6fbba5011d..ec9df57ceed 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.h +++ b/src/plugins/cpptools/baseeditordocumentprocessor.h @@ -74,8 +74,9 @@ public: using HeaderErrorDiagnosticWidgetCreator = std::function; signals: - // Signal interface to implement + void projectPartInfoUpdated(const CppTools::ProjectPartInfo &projectPartInfo); + void codeWarningsUpdated(unsigned revision, const QList selections, const HeaderErrorDiagnosticWidgetCreator &creator, diff --git a/src/plugins/cpptools/builtineditordocumentparser.cpp b/src/plugins/cpptools/builtineditordocumentparser.cpp index 5243e2a76bb..236a95f3260 100644 --- a/src/plugins/cpptools/builtineditordocumentparser.cpp +++ b/src/plugins/cpptools/builtineditordocumentparser.cpp @@ -77,19 +77,20 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface &futur QString projectConfigFile; LanguageFeatures features = LanguageFeatures::defaultFeatures(); - baseState.projectPart = determineProjectPart(filePath(), - baseConfig, - baseState, - updateParams.activeProject, - updateParams.languagePreference, - updateParams.hasActiveProjectChanged); + baseState.projectPartInfo = determineProjectPart(filePath(), + baseConfig, + baseState, + updateParams.activeProject, + updateParams.languagePreference, + updateParams.hasActiveProjectChanged); + emit projectPartInfoUpdated(baseState.projectPartInfo); if (state.forceSnapshotInvalidation) { invalidateSnapshot = true; state.forceSnapshotInvalidation = false; } - if (const ProjectPart::Ptr part = baseState.projectPart) { + if (const ProjectPart::Ptr part = baseState.projectPartInfo.projectPart) { configFile += part->toolchainDefines; configFile += overwrittenToolchainDefines(*part.data()); configFile += part->projectDefines; diff --git a/src/plugins/cpptools/builtineditordocumentprocessor.cpp b/src/plugins/cpptools/builtineditordocumentprocessor.cpp index 2a6dd066d11..9dbbb45383a 100644 --- a/src/plugins/cpptools/builtineditordocumentprocessor.cpp +++ b/src/plugins/cpptools/builtineditordocumentprocessor.cpp @@ -190,6 +190,8 @@ BuiltinEditorDocumentProcessor::BuiltinEditorDocumentProcessor( }); } + connect(m_parser.data(), &BuiltinEditorDocumentParser::projectPartInfoUpdated, + this, &BaseEditorDocumentProcessor::projectPartInfoUpdated); connect(m_parser.data(), &BuiltinEditorDocumentParser::finished, this, &BuiltinEditorDocumentProcessor::onParserFinished); connect(&m_semanticInfoUpdater, &SemanticInfoUpdater::updated, diff --git a/src/plugins/cpptools/cppmodelmanager_test.cpp b/src/plugins/cpptools/cppmodelmanager_test.cpp index fb65fe93f0d..0248e3ac8ec 100644 --- a/src/plugins/cpptools/cppmodelmanager_test.cpp +++ b/src/plugins/cpptools/cppmodelmanager_test.cpp @@ -167,7 +167,7 @@ ProjectPart::Ptr projectPartOfEditorDocument(const QString &filePath) { auto *editorDocument = CppModelManager::instance()->cppEditorDocument(filePath); QTC_ASSERT(editorDocument, return ProjectPart::Ptr()); - return editorDocument->processor()->parser()->projectPart(); + return editorDocument->processor()->parser()->projectPartInfo().projectPart; } } // anonymous namespace diff --git a/src/plugins/cpptools/cppprojectpartchooser.cpp b/src/plugins/cpptools/cppprojectpartchooser.cpp index 5f7d3de1370..816bddb5928 100644 --- a/src/plugins/cpptools/cppprojectpartchooser.cpp +++ b/src/plugins/cpptools/cppprojectpartchooser.cpp @@ -31,82 +31,144 @@ namespace CppTools { namespace Internal { -static bool isPreferredLanguage(const ProjectPart &projectPart, Language preference) +class ProjectPartPrioritizer { - const bool isCProjectPart = projectPart.languageVersion <= ProjectPart::LatestCVersion; - return (preference == Language::C && isCProjectPart) - || (preference == Language::Cxx && !isCProjectPart); -} +public: + struct PrioritizedProjectPart + { + PrioritizedProjectPart(const ProjectPart::Ptr &projectPart, int priority) + : projectPart(projectPart) , priority(priority) {} -static int priority(const ProjectPart &projectPart, - const ProjectExplorer::Project *activeProject, - Language languagePreference) -{ - int thePriority = 0; - - if (projectPart.project == activeProject) - thePriority += 100; - - if (projectPart.selectedForBuilding) - thePriority += 10; - - if (isPreferredLanguage(projectPart, languagePreference)) - thePriority += 1; - - return thePriority; -} - -static ProjectPart::Ptr chooseFromMultiple(const QList &projectParts, - const ProjectExplorer::Project *activeProject, - Language languagePreference) -{ - QList projectPartsPrioritized = projectParts; - const auto lessThan = [&] (const ProjectPart::Ptr &p1, const ProjectPart::Ptr &p2) { - return priority(*p1, activeProject, languagePreference) - > priority(*p2, activeProject, languagePreference); + ProjectPart::Ptr projectPart; + int priority = 0; }; - std::stable_sort(projectPartsPrioritized.begin(), projectPartsPrioritized.end(), lessThan); - return projectPartsPrioritized.first(); -} + ProjectPartPrioritizer(const QList &projectParts, + const ProjectExplorer::Project *activeProject, + Language languagePreference) + : m_projectParts(projectParts) + , m_activeProject(activeProject) + , m_languagePreference(languagePreference) + { + // Determine best project part + const QList prioritized = prioritize(); + m_projectPart = prioritized.first().projectPart; -ProjectPart::Ptr ProjectPartChooser::choose(const QString &filePath, - const ProjectPart::Ptr ¤tProjectPart, - const ProjectPart::Ptr &manuallySetProjectPart, - bool stickToPreviousProjectPart, - const ProjectExplorer::Project *activeProject, - Language languagePreference, - bool projectHasChanged) const + // Determine ambiguity + m_isAmbiguous = prioritized.size() > 1 + ? prioritized[0].priority == prioritized[1].priority + : false; + } + + ProjectPart::Ptr projectPart() + { + return m_projectPart; + } + + bool isAmbiguous() const + { + return m_isAmbiguous; + } + +private: + QList prioritize() + { + // Prioritize + QList prioritized = Utils::transform(m_projectParts, + [&](const ProjectPart::Ptr &projectPart) { + return PrioritizedProjectPart{projectPart, priority(*projectPart)}; + }); + + // Sort according to priority + const auto lessThan = [&] (const PrioritizedProjectPart &p1, + const PrioritizedProjectPart &p2) { + return p1.priority > p2.priority; + }; + std::stable_sort(prioritized.begin(), prioritized.end(), lessThan); + + return prioritized; + } + + int priority(const ProjectPart &projectPart) const + { + int thePriority = 0; + + if (projectPart.project == m_activeProject) + thePriority += 100; + + if (projectPart.selectedForBuilding) + thePriority += 10; + + if (isPreferredLanguage(projectPart)) + thePriority += 1; + + return thePriority; + } + + bool isPreferredLanguage(const ProjectPart &projectPart) const + { + const bool isCProjectPart = projectPart.languageVersion <= ProjectPart::LatestCVersion; + return (m_languagePreference == Language::C && isCProjectPart) + || (m_languagePreference == Language::Cxx && !isCProjectPart); + } + +private: + const QList m_projectParts; + const ProjectExplorer::Project *m_activeProject = nullptr; + Language m_languagePreference = Language::Cxx; + + // Results + ProjectPart::Ptr m_projectPart; + bool m_isAmbiguous = false; +}; + +ProjectPartInfo ProjectPartChooser::choose( + const QString &filePath, + const ProjectPart::Ptr ¤tProjectPart, + const ProjectPart::Ptr &manuallySetProjectPart, + bool stickToPreviousProjectPart, + const ProjectExplorer::Project *activeProject, + Language languagePreference, + bool projectHasChanged) const { QTC_CHECK(m_projectPartsForFile); QTC_CHECK(m_projectPartsFromDependenciesForFile); QTC_CHECK(m_fallbackProjectPart); if (manuallySetProjectPart) - return manuallySetProjectPart; + return {manuallySetProjectPart, ProjectPartInfo::NoHint}; ProjectPart::Ptr projectPart = currentProjectPart; + ProjectPartInfo::Hint hint = ProjectPartInfo::NoHint; QList projectParts = m_projectPartsForFile(filePath); if (projectParts.isEmpty()) { if (projectPart && stickToPreviousProjectPart) // File is not directly part of any project, but we got one before. We will re-use it, // because re-calculating this can be expensive when the dependency table is big. - return projectPart; + return {projectPart, ProjectPartInfo::NoHint}; // Fall-back step 1: Get some parts through the dependency table: projectParts = m_projectPartsFromDependenciesForFile(filePath); - if (projectParts.isEmpty()) + if (projectParts.isEmpty()) { // Fall-back step 2: Use fall-back part from the model manager: projectPart = m_fallbackProjectPart(); - else - projectPart = chooseFromMultiple(projectParts, activeProject, languagePreference); + hint = ProjectPartInfo::IsFallbackMatch; + } else { + ProjectPartPrioritizer prioritizer(projectParts, activeProject, languagePreference); + projectPart = prioritizer.projectPart(); + } } else { - if (projectHasChanged || !projectParts.contains(projectPart)) - projectPart = chooseFromMultiple(projectParts, activeProject, languagePreference); + if (projectHasChanged || !projectParts.contains(projectPart)) { + ProjectPartPrioritizer prioritizer(projectParts, activeProject, languagePreference); + projectPart = prioritizer.projectPart(); + hint = prioritizer.isAmbiguous() + ? ProjectPartInfo::IsAmbiguousMatch + : ProjectPartInfo::NoHint; + } } - return projectPart; + return {projectPart, hint}; } void ProjectPartChooser::setFallbackProjectPart(const FallBackProjectPart &getter) diff --git a/src/plugins/cpptools/cppprojectpartchooser.h b/src/plugins/cpptools/cppprojectpartchooser.h index e0a8581c344..940c2c092ed 100644 --- a/src/plugins/cpptools/cppprojectpartchooser.h +++ b/src/plugins/cpptools/cppprojectpartchooser.h @@ -25,7 +25,7 @@ #pragma once -#include "cpplanguage.h" +#include "cpptools_utils.h" #include "projectpart.h" #include @@ -48,13 +48,14 @@ public: void setProjectPartsForFile(const ProjectPartsForFile &getter); void setProjectPartsFromDependenciesForFile(const ProjectPartsFromDependenciesForFile &getter); - ProjectPart::Ptr choose(const QString &filePath, - const ProjectPart::Ptr ¤tProjectPart, - const ProjectPart::Ptr &manuallySetProjectPart, - bool stickToPreviousProjectPart, - const ProjectExplorer::Project *activeProject, - Language languagePreference, - bool projectHasChanged) const; + ProjectPartInfo choose( + const QString &filePath, + const ProjectPart::Ptr ¤tProjectPart, + const ProjectPart::Ptr &manuallySetProjectPart, + bool stickToPreviousProjectPart, + const ProjectExplorer::Project *activeProject, + Language languagePreference, + bool projectHasChanged) const; private: FallBackProjectPart m_fallbackProjectPart; diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 9b3b064b777..f65ffdd7645 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -34,7 +34,6 @@ HEADERS += \ cppfunctionsfilter.h \ cppincludesfilter.h \ cppindexingsupport.h \ - cpplanguage.h \ cpplocalsymbols.h \ cpplocatordata.h \ cpplocatorfilter.h \ @@ -50,6 +49,7 @@ HEADERS += \ cppsemanticinfoupdater.h \ cppsourceprocessor.h \ cpptools_global.h \ + cpptools_utils.h \ cpptoolsconstants.h \ cpptoolsjsextension.h \ cpptoolsplugin.h \ diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index f7047ed28dd..c05db793a4f 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -61,7 +61,6 @@ Project { "cppfunctionsfilter.cpp", "cppfunctionsfilter.h", "cppincludesfilter.cpp", "cppincludesfilter.h", "cppindexingsupport.cpp", "cppindexingsupport.h", - "cpplanguage.h", "cpplocalsymbols.cpp", "cpplocalsymbols.h", "cpplocatordata.cpp", "cpplocatordata.h", "cpplocatorfilter.cpp", "cpplocatorfilter.h", @@ -81,6 +80,7 @@ Project { "cpptoolsbridgeqtcreatorimplementation.cpp", "cpptoolsbridgeqtcreatorimplementation.h", "cpptools.qrc", "cpptools_global.h", + "cpptools_utils.h", "cpptoolsconstants.h", "cpptoolsjsextension.cpp", "cpptoolsjsextension.h", "cpptoolsplugin.cpp", "cpptoolsplugin.h", diff --git a/src/plugins/cpptools/cpplanguage.h b/src/plugins/cpptools/cpptools_utils.h similarity index 86% rename from src/plugins/cpptools/cpplanguage.h rename to src/plugins/cpptools/cpptools_utils.h index 2a84641d4de..a90805a7ab0 100644 --- a/src/plugins/cpptools/cpplanguage.h +++ b/src/plugins/cpptools/cpptools_utils.h @@ -25,8 +25,23 @@ #pragma once +#include "projectpart.h" + namespace CppTools { enum class Language { C, Cxx }; +class ProjectPartInfo { +public: + enum Hint { + NoHint, + IsFallbackMatch, + IsAmbiguousMatch + }; + +public: + ProjectPart::Ptr projectPart; + Hint hint; +}; + } // namespace CppTools diff --git a/src/plugins/cpptools/cpptoolsbridgeqtcreatorimplementation.cpp b/src/plugins/cpptools/cpptoolsbridgeqtcreatorimplementation.cpp index 7b9eb69ca13..e0b6b9fdab8 100644 --- a/src/plugins/cpptools/cpptoolsbridgeqtcreatorimplementation.cpp +++ b/src/plugins/cpptools/cpptoolsbridgeqtcreatorimplementation.cpp @@ -47,7 +47,7 @@ namespace { CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath) { if (const auto parser = BaseEditorDocumentParser::get(filePath)) - return parser->projectPart(); + return parser->projectPartInfo().projectPart; return CppTools::ProjectPart::Ptr(); } diff --git a/tests/unit/unittest/cppprojectpartchooser-test.cpp b/tests/unit/unittest/cppprojectpartchooser-test.cpp index aed61b3f610..47a47de9bea 100644 --- a/tests/unit/unittest/cppprojectpartchooser-test.cpp +++ b/tests/unit/unittest/cppprojectpartchooser-test.cpp @@ -25,12 +25,13 @@ #include "googletest.h" -#include #include +#include #include using CppTools::Internal::ProjectPartChooser; using CppTools::ProjectPart; +using CppTools::ProjectPartInfo; using CppTools::Language; using testing::Eq; @@ -41,7 +42,7 @@ class ProjectPartChooser : public ::testing::Test { protected: void SetUp() override; - const ProjectPart::Ptr choose() const; + const ProjectPartInfo choose() const; static QList createProjectPartsWithDifferentProjects(); static QList createCAndCxxProjectParts(); @@ -65,7 +66,7 @@ TEST_F(ProjectPartChooser, ChooseManuallySet) { manuallySetProjectPart.reset(new ProjectPart); - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(manuallySetProjectPart)); } @@ -76,7 +77,7 @@ TEST_F(ProjectPartChooser, ForMultipleChoosePrevious) projectPartsForFile += otherProjectPart; projectPartsForFile += currentProjectPart; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(currentProjectPart)); } @@ -88,7 +89,7 @@ TEST_F(ProjectPartChooser, ForMultipleChooseFromActiveProject) projectPartsForFile += projectParts; activeProject = secondProjectPart->project; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(secondProjectPart)); } @@ -102,7 +103,7 @@ TEST_F(ProjectPartChooser, ForMultiplePreferSelectedForBuilding) projectPartsForFile += firstProjectPart; projectPartsForFile += secondProjectPart; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(secondProjectPart)); } @@ -114,7 +115,7 @@ TEST_F(ProjectPartChooser, ForMultipleFromDependenciesChooseFromActiveProject) projectPartsFromDependenciesForFile += projectParts; activeProject = secondProjectPart->project; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(secondProjectPart)); } @@ -129,7 +130,7 @@ TEST_F(ProjectPartChooser, ForMultipleCheckIfActiveProjectChanged) activeProject = secondProjectPart->project; projectHasChanged = true; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(secondProjectPart)); } @@ -140,7 +141,7 @@ TEST_F(ProjectPartChooser, ForMultipleAndAmbigiousHeaderPreferCProjectPart) projectPartsForFile = createCAndCxxProjectParts(); const ProjectPart::Ptr cProjectPart = projectPartsForFile.at(0); - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(cProjectPart)); } @@ -151,16 +152,27 @@ TEST_F(ProjectPartChooser, ForMultipleAndAmbigiousHeaderPreferCxxProjectPart) projectPartsForFile = createCAndCxxProjectParts(); const ProjectPart::Ptr cxxProjectPart = projectPartsForFile.at(1); - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(cxxProjectPart)); } +TEST_F(ProjectPartChooser, IndicateMultiple) +{ + const ProjectPart::Ptr p1{new ProjectPart}; + const ProjectPart::Ptr p2{new ProjectPart}; + projectPartsForFile += { p1, p2 }; + + const ProjectPartInfo::Hint hint = choose().hint; + + ASSERT_THAT(hint, Eq(ProjectPartInfo::Hint::IsAmbiguousMatch)); +} + TEST_F(ProjectPartChooser, IfProjectIsGoneStickToPrevious) // Built-in Code Model { stickToPreviousProjectPart = true; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(currentProjectPart)); } @@ -170,7 +182,7 @@ TEST_F(ProjectPartChooser, IfProjectIsGoneDoNotStickToPrevious) // Clang Code Mo currentProjectPart.clear(); stickToPreviousProjectPart = true; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(ProjectPart::Ptr())); } @@ -180,7 +192,7 @@ TEST_F(ProjectPartChooser, ForMultipleChooseNewIfPreviousIsGone) const ProjectPart::Ptr newProjectPart{new ProjectPart}; projectPartsForFile += newProjectPart; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(newProjectPart)); } @@ -190,7 +202,7 @@ TEST_F(ProjectPartChooser, FallbackToProjectPartFromDependencies) const ProjectPart::Ptr fromDependencies{new ProjectPart}; projectPartsFromDependenciesForFile += fromDependencies; - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(fromDependencies)); } @@ -199,11 +211,20 @@ TEST_F(ProjectPartChooser, FallbackToProjectPartFromModelManager) { fallbackProjectPart.reset(new ProjectPart); - const ProjectPart::Ptr chosen = choose(); + const ProjectPart::Ptr chosen = choose().projectPart; ASSERT_THAT(chosen, Eq(fallbackProjectPart)); } +TEST_F(ProjectPartChooser, IndicateFallbacktoProjectPartFromModelManager) +{ + fallbackProjectPart.reset(new ProjectPart); + + const ProjectPartInfo::Hint hint = choose().hint; + + ASSERT_THAT(hint, Eq(ProjectPartInfo::Hint::IsFallbackMatch)); +} + void ProjectPartChooser::SetUp() { chooser.setFallbackProjectPart([&](){ @@ -217,7 +238,7 @@ void ProjectPartChooser::SetUp() }); } -const ProjectPart::Ptr ProjectPartChooser::choose() const +const ProjectPartInfo ProjectPartChooser::choose() const { return chooser.choose(filePath, currentProjectPart,