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 <david.schulz@qt.io>
This commit is contained in:
Nikolai Kosjar
2017-01-17 15:27:31 +01:00
parent 19eaf87ef9
commit 0b8df41387
19 changed files with 235 additions and 116 deletions

View File

@@ -39,12 +39,13 @@ void ClangEditorDocumentParser::updateImpl(const QFutureInterface<void> &,
const UpdateParams &updateParams) const UpdateParams &updateParams)
{ {
State state_ = state(); State state_ = state();
state_.projectPart = determineProjectPart(filePath(), state_.projectPartInfo = determineProjectPart(filePath(),
configuration(), configuration(),
state_, state_,
updateParams.activeProject, updateParams.activeProject,
updateParams.languagePreference, updateParams.languagePreference,
updateParams.hasActiveProjectChanged); updateParams.hasActiveProjectChanged);
emit projectPartInfoUpdated(state_.projectPartInfo);
setState(state_); setState(state_);
} }

View File

@@ -80,6 +80,9 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
connect(&m_updateTranslationUnitTimer, &QTimer::timeout, connect(&m_updateTranslationUnitTimer, &QTimer::timeout,
this, &ClangEditorDocumentProcessor::updateTranslationUnitIfProjectPartExists); 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 // 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. // editor (widget) related features that are not yet implemented by the clang plugin.
connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::cppDocumentUpdated, connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::cppDocumentUpdated,
@@ -302,7 +305,7 @@ static bool isProjectPartLoadedOrIsFallback(CppTools::ProjectPart::Ptr projectPa
void ClangEditorDocumentProcessor::updateProjectPartAndTranslationUnitForEditor() void ClangEditorDocumentProcessor::updateProjectPartAndTranslationUnitForEditor()
{ {
const CppTools::ProjectPart::Ptr projectPart = m_parser->projectPart(); const CppTools::ProjectPart::Ptr projectPart = m_parser->projectPartInfo().projectPart;
if (isProjectPartLoadedOrIsFallback(projectPart)) { if (isProjectPartLoadedOrIsFallback(projectPart)) {
registerTranslationUnitForEditor(projectPart.data()); registerTranslationUnitForEditor(projectPart.data());

View File

@@ -131,7 +131,7 @@ QStringList createClangOptions(const ProjectPart::Ptr &pPart, ProjectFile::Kind
ProjectPart::Ptr projectPartForFile(const QString &filePath) ProjectPart::Ptr projectPartForFile(const QString &filePath)
{ {
if (const auto parser = CppTools::BaseEditorDocumentParser::get(filePath)) if (const auto parser = CppTools::BaseEditorDocumentParser::get(filePath))
return parser->projectPart(); return parser->projectPartInfo().projectPart;
return ProjectPart::Ptr(); return ProjectPart::Ptr();
} }

View File

@@ -1580,7 +1580,7 @@ void CppCodeModelInspectorDialog::refresh()
// Project Parts // Project Parts
const ProjectPart::Ptr editorsProjectPart = cppEditorDocument const ProjectPart::Ptr editorsProjectPart = cppEditorDocument
? cppEditorDocument->processor()->parser()->projectPart() ? cppEditorDocument->processor()->parser()->projectPartInfo().projectPart
: ProjectPart::Ptr(); : ProjectPart::Ptr();
const QList<ProjectInfo> projectInfos = cmmi->projectInfos(); const QList<ProjectInfo> projectInfos = cmmi->projectInfos();

View File

@@ -274,7 +274,8 @@ void CppEditorDocument::setPreprocessorSettings(const CppTools::ProjectPart::Ptr
{ {
const auto parser = processor()->parser(); const auto parser = processor()->parser();
QTC_ASSERT(parser, return); 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(); CppTools::BaseEditorDocumentParser::Configuration config = parser->configuration();
config.manuallySetProjectPart = projectPart; config.manuallySetProjectPart = projectPart;
config.editorDefines = defines; config.editorDefines = defines;

View File

@@ -54,6 +54,8 @@ namespace CppTools {
BaseEditorDocumentParser::BaseEditorDocumentParser(const QString &filePath) BaseEditorDocumentParser::BaseEditorDocumentParser(const QString &filePath)
: m_filePath(filePath) : m_filePath(filePath)
{ {
static int meta = qRegisterMetaType<ProjectPartInfo>("CppTools::ProjectPartInfo");
Q_UNUSED(meta);
} }
BaseEditorDocumentParser::~BaseEditorDocumentParser() BaseEditorDocumentParser::~BaseEditorDocumentParser()
@@ -102,9 +104,9 @@ void BaseEditorDocumentParser::setState(const State &state)
m_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) BaseEditorDocumentParser::Ptr BaseEditorDocumentParser::get(const QString &filePath)
@@ -117,7 +119,7 @@ BaseEditorDocumentParser::Ptr BaseEditorDocumentParser::get(const QString &fileP
return BaseEditorDocumentParser::Ptr(); return BaseEditorDocumentParser::Ptr();
} }
ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart( ProjectPartInfo BaseEditorDocumentParser::determineProjectPart(
const QString &filePath, const QString &filePath,
const Configuration &config, const Configuration &config,
const State &state, const State &state,
@@ -125,7 +127,9 @@ ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart(
Language languagePreference, Language languagePreference,
bool hasActiveProjectChanged) bool hasActiveProjectChanged)
{ {
Internal::ProjectPartChooser chooser; using Internal::ProjectPartChooser;
ProjectPartChooser chooser;
chooser.setFallbackProjectPart([](){ chooser.setFallbackProjectPart([](){
return CppModelManager::instance()->fallbackProjectPart(); return CppModelManager::instance()->fallbackProjectPart();
}); });
@@ -137,13 +141,16 @@ ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart(
return CppModelManager::instance()->projectPartFromDependencies(fileName); return CppModelManager::instance()->projectPartFromDependencies(fileName);
}); });
return chooser.choose(filePath, const ProjectPartInfo chooserResult
state.projectPart, = chooser.choose(filePath,
config.manuallySetProjectPart, state.projectPartInfo.projectPart,
config.stickToPreviousProjectPart, config.manuallySetProjectPart,
activeProject, config.stickToPreviousProjectPart,
languagePreference, activeProject,
hasActiveProjectChanged); languagePreference,
hasActiveProjectChanged);
return chooserResult;
} }
} // namespace CppTools } // namespace CppTools

View File

@@ -25,8 +25,8 @@
#pragma once #pragma once
#include "cpplanguage.h"
#include "cpptools_global.h" #include "cpptools_global.h"
#include "cpptools_utils.h"
#include "cppworkingcopy.h" #include "cppworkingcopy.h"
#include "projectpart.h" #include "projectpart.h"
@@ -82,22 +82,26 @@ public:
void update(const UpdateParams &updateParams); void update(const UpdateParams &updateParams);
void update(const QFutureInterface<void> &future, const UpdateParams &updateParams); void update(const QFutureInterface<void> &future, const UpdateParams &updateParams);
ProjectPart::Ptr projectPart() const; ProjectPartInfo projectPartInfo() const;
signals:
void projectPartInfoUpdated(const CppTools::ProjectPartInfo &projectPartInfo);
protected: protected:
struct State { struct State {
QByteArray editorDefines; QByteArray editorDefines;
ProjectPart::Ptr projectPart; ProjectPartInfo projectPartInfo;
}; };
State state() const; State state() const;
void setState(const State &state); void setState(const State &state);
static ProjectPart::Ptr determineProjectPart(const QString &filePath, static ProjectPartInfo determineProjectPart(
const Configuration &config, const QString &filePath,
const State &state, const Configuration &config,
const ProjectExplorer::Project *activeProject, const State &state,
Language languagePreference, const ProjectExplorer::Project *activeProject,
bool hasActiveProjectChanged); Language languagePreference,
bool hasActiveProjectChanged);
mutable QMutex m_stateAndConfigurationMutex; mutable QMutex m_stateAndConfigurationMutex;

View File

@@ -26,10 +26,10 @@
#include "baseeditordocumentprocessor.h" #include "baseeditordocumentprocessor.h"
#include "cppcodemodelsettings.h" #include "cppcodemodelsettings.h"
#include "cpplanguage.h"
#include "cppmodelmanager.h" #include "cppmodelmanager.h"
#include "cpptoolsbridge.h" #include "cpptoolsbridge.h"
#include "cpptoolsreuse.h" #include "cpptoolsreuse.h"
#include "cpptools_utils.h"
#include "editordocumenthandle.h" #include "editordocumenthandle.h"
#include <projectexplorer/session.h> #include <projectexplorer/session.h>

View File

@@ -74,8 +74,9 @@ public:
using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>; using HeaderErrorDiagnosticWidgetCreator = std::function<QWidget*()>;
signals: signals:
// Signal interface to implement // Signal interface to implement
void projectPartInfoUpdated(const CppTools::ProjectPartInfo &projectPartInfo);
void codeWarningsUpdated(unsigned revision, void codeWarningsUpdated(unsigned revision,
const QList<QTextEdit::ExtraSelection> selections, const QList<QTextEdit::ExtraSelection> selections,
const HeaderErrorDiagnosticWidgetCreator &creator, const HeaderErrorDiagnosticWidgetCreator &creator,

View File

@@ -77,19 +77,20 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface<void> &futur
QString projectConfigFile; QString projectConfigFile;
LanguageFeatures features = LanguageFeatures::defaultFeatures(); LanguageFeatures features = LanguageFeatures::defaultFeatures();
baseState.projectPart = determineProjectPart(filePath(), baseState.projectPartInfo = determineProjectPart(filePath(),
baseConfig, baseConfig,
baseState, baseState,
updateParams.activeProject, updateParams.activeProject,
updateParams.languagePreference, updateParams.languagePreference,
updateParams.hasActiveProjectChanged); updateParams.hasActiveProjectChanged);
emit projectPartInfoUpdated(baseState.projectPartInfo);
if (state.forceSnapshotInvalidation) { if (state.forceSnapshotInvalidation) {
invalidateSnapshot = true; invalidateSnapshot = true;
state.forceSnapshotInvalidation = false; state.forceSnapshotInvalidation = false;
} }
if (const ProjectPart::Ptr part = baseState.projectPart) { if (const ProjectPart::Ptr part = baseState.projectPartInfo.projectPart) {
configFile += part->toolchainDefines; configFile += part->toolchainDefines;
configFile += overwrittenToolchainDefines(*part.data()); configFile += overwrittenToolchainDefines(*part.data());
configFile += part->projectDefines; configFile += part->projectDefines;

View File

@@ -190,6 +190,8 @@ BuiltinEditorDocumentProcessor::BuiltinEditorDocumentProcessor(
}); });
} }
connect(m_parser.data(), &BuiltinEditorDocumentParser::projectPartInfoUpdated,
this, &BaseEditorDocumentProcessor::projectPartInfoUpdated);
connect(m_parser.data(), &BuiltinEditorDocumentParser::finished, connect(m_parser.data(), &BuiltinEditorDocumentParser::finished,
this, &BuiltinEditorDocumentProcessor::onParserFinished); this, &BuiltinEditorDocumentProcessor::onParserFinished);
connect(&m_semanticInfoUpdater, &SemanticInfoUpdater::updated, connect(&m_semanticInfoUpdater, &SemanticInfoUpdater::updated,

View File

@@ -167,7 +167,7 @@ ProjectPart::Ptr projectPartOfEditorDocument(const QString &filePath)
{ {
auto *editorDocument = CppModelManager::instance()->cppEditorDocument(filePath); auto *editorDocument = CppModelManager::instance()->cppEditorDocument(filePath);
QTC_ASSERT(editorDocument, return ProjectPart::Ptr()); QTC_ASSERT(editorDocument, return ProjectPart::Ptr());
return editorDocument->processor()->parser()->projectPart(); return editorDocument->processor()->parser()->projectPartInfo().projectPart;
} }
} // anonymous namespace } // anonymous namespace

View File

@@ -31,82 +31,144 @@
namespace CppTools { namespace CppTools {
namespace Internal { namespace Internal {
static bool isPreferredLanguage(const ProjectPart &projectPart, Language preference) class ProjectPartPrioritizer
{ {
const bool isCProjectPart = projectPart.languageVersion <= ProjectPart::LatestCVersion; public:
return (preference == Language::C && isCProjectPart) struct PrioritizedProjectPart
|| (preference == Language::Cxx && !isCProjectPart); {
} PrioritizedProjectPart(const ProjectPart::Ptr &projectPart, int priority)
: projectPart(projectPart) , priority(priority) {}
static int priority(const ProjectPart &projectPart, ProjectPart::Ptr projectPart;
const ProjectExplorer::Project *activeProject, int priority = 0;
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<ProjectPart::Ptr> &projectParts,
const ProjectExplorer::Project *activeProject,
Language languagePreference)
{
QList<ProjectPart::Ptr> projectPartsPrioritized = projectParts;
const auto lessThan = [&] (const ProjectPart::Ptr &p1, const ProjectPart::Ptr &p2) {
return priority(*p1, activeProject, languagePreference)
> priority(*p2, activeProject, languagePreference);
}; };
std::stable_sort(projectPartsPrioritized.begin(), projectPartsPrioritized.end(), lessThan);
return projectPartsPrioritized.first(); ProjectPartPrioritizer(const QList<ProjectPart::Ptr> &projectParts,
} const ProjectExplorer::Project *activeProject,
Language languagePreference)
: m_projectParts(projectParts)
, m_activeProject(activeProject)
, m_languagePreference(languagePreference)
{
// Determine best project part
const QList<PrioritizedProjectPart> prioritized = prioritize();
m_projectPart = prioritized.first().projectPart;
ProjectPart::Ptr ProjectPartChooser::choose(const QString &filePath, // Determine ambiguity
const ProjectPart::Ptr &currentProjectPart, m_isAmbiguous = prioritized.size() > 1
const ProjectPart::Ptr &manuallySetProjectPart, ? prioritized[0].priority == prioritized[1].priority
bool stickToPreviousProjectPart, : false;
const ProjectExplorer::Project *activeProject, }
Language languagePreference,
bool projectHasChanged) const ProjectPart::Ptr projectPart()
{
return m_projectPart;
}
bool isAmbiguous() const
{
return m_isAmbiguous;
}
private:
QList<PrioritizedProjectPart> prioritize()
{
// Prioritize
QList<PrioritizedProjectPart> 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<ProjectPart::Ptr> 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 &currentProjectPart,
const ProjectPart::Ptr &manuallySetProjectPart,
bool stickToPreviousProjectPart,
const ProjectExplorer::Project *activeProject,
Language languagePreference,
bool projectHasChanged) const
{ {
QTC_CHECK(m_projectPartsForFile); QTC_CHECK(m_projectPartsForFile);
QTC_CHECK(m_projectPartsFromDependenciesForFile); QTC_CHECK(m_projectPartsFromDependenciesForFile);
QTC_CHECK(m_fallbackProjectPart); QTC_CHECK(m_fallbackProjectPart);
if (manuallySetProjectPart) if (manuallySetProjectPart)
return manuallySetProjectPart; return {manuallySetProjectPart, ProjectPartInfo::NoHint};
ProjectPart::Ptr projectPart = currentProjectPart; ProjectPart::Ptr projectPart = currentProjectPart;
ProjectPartInfo::Hint hint = ProjectPartInfo::NoHint;
QList<ProjectPart::Ptr> projectParts = m_projectPartsForFile(filePath); QList<ProjectPart::Ptr> projectParts = m_projectPartsForFile(filePath);
if (projectParts.isEmpty()) { if (projectParts.isEmpty()) {
if (projectPart && stickToPreviousProjectPart) if (projectPart && stickToPreviousProjectPart)
// File is not directly part of any project, but we got one before. We will re-use it, // 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. // 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: // Fall-back step 1: Get some parts through the dependency table:
projectParts = m_projectPartsFromDependenciesForFile(filePath); projectParts = m_projectPartsFromDependenciesForFile(filePath);
if (projectParts.isEmpty()) if (projectParts.isEmpty()) {
// Fall-back step 2: Use fall-back part from the model manager: // Fall-back step 2: Use fall-back part from the model manager:
projectPart = m_fallbackProjectPart(); projectPart = m_fallbackProjectPart();
else hint = ProjectPartInfo::IsFallbackMatch;
projectPart = chooseFromMultiple(projectParts, activeProject, languagePreference); } else {
ProjectPartPrioritizer prioritizer(projectParts, activeProject, languagePreference);
projectPart = prioritizer.projectPart();
}
} else { } else {
if (projectHasChanged || !projectParts.contains(projectPart)) if (projectHasChanged || !projectParts.contains(projectPart)) {
projectPart = chooseFromMultiple(projectParts, activeProject, languagePreference); 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) void ProjectPartChooser::setFallbackProjectPart(const FallBackProjectPart &getter)

View File

@@ -25,7 +25,7 @@
#pragma once #pragma once
#include "cpplanguage.h" #include "cpptools_utils.h"
#include "projectpart.h" #include "projectpart.h"
#include <functional> #include <functional>
@@ -48,13 +48,14 @@ public:
void setProjectPartsForFile(const ProjectPartsForFile &getter); void setProjectPartsForFile(const ProjectPartsForFile &getter);
void setProjectPartsFromDependenciesForFile(const ProjectPartsFromDependenciesForFile &getter); void setProjectPartsFromDependenciesForFile(const ProjectPartsFromDependenciesForFile &getter);
ProjectPart::Ptr choose(const QString &filePath, ProjectPartInfo choose(
const ProjectPart::Ptr &currentProjectPart, const QString &filePath,
const ProjectPart::Ptr &manuallySetProjectPart, const ProjectPart::Ptr &currentProjectPart,
bool stickToPreviousProjectPart, const ProjectPart::Ptr &manuallySetProjectPart,
const ProjectExplorer::Project *activeProject, bool stickToPreviousProjectPart,
Language languagePreference, const ProjectExplorer::Project *activeProject,
bool projectHasChanged) const; Language languagePreference,
bool projectHasChanged) const;
private: private:
FallBackProjectPart m_fallbackProjectPart; FallBackProjectPart m_fallbackProjectPart;

View File

@@ -34,7 +34,6 @@ HEADERS += \
cppfunctionsfilter.h \ cppfunctionsfilter.h \
cppincludesfilter.h \ cppincludesfilter.h \
cppindexingsupport.h \ cppindexingsupport.h \
cpplanguage.h \
cpplocalsymbols.h \ cpplocalsymbols.h \
cpplocatordata.h \ cpplocatordata.h \
cpplocatorfilter.h \ cpplocatorfilter.h \
@@ -50,6 +49,7 @@ HEADERS += \
cppsemanticinfoupdater.h \ cppsemanticinfoupdater.h \
cppsourceprocessor.h \ cppsourceprocessor.h \
cpptools_global.h \ cpptools_global.h \
cpptools_utils.h \
cpptoolsconstants.h \ cpptoolsconstants.h \
cpptoolsjsextension.h \ cpptoolsjsextension.h \
cpptoolsplugin.h \ cpptoolsplugin.h \

View File

@@ -61,7 +61,6 @@ Project {
"cppfunctionsfilter.cpp", "cppfunctionsfilter.h", "cppfunctionsfilter.cpp", "cppfunctionsfilter.h",
"cppincludesfilter.cpp", "cppincludesfilter.h", "cppincludesfilter.cpp", "cppincludesfilter.h",
"cppindexingsupport.cpp", "cppindexingsupport.h", "cppindexingsupport.cpp", "cppindexingsupport.h",
"cpplanguage.h",
"cpplocalsymbols.cpp", "cpplocalsymbols.h", "cpplocalsymbols.cpp", "cpplocalsymbols.h",
"cpplocatordata.cpp", "cpplocatordata.h", "cpplocatordata.cpp", "cpplocatordata.h",
"cpplocatorfilter.cpp", "cpplocatorfilter.h", "cpplocatorfilter.cpp", "cpplocatorfilter.h",
@@ -81,6 +80,7 @@ Project {
"cpptoolsbridgeqtcreatorimplementation.cpp", "cpptoolsbridgeqtcreatorimplementation.h", "cpptoolsbridgeqtcreatorimplementation.cpp", "cpptoolsbridgeqtcreatorimplementation.h",
"cpptools.qrc", "cpptools.qrc",
"cpptools_global.h", "cpptools_global.h",
"cpptools_utils.h",
"cpptoolsconstants.h", "cpptoolsconstants.h",
"cpptoolsjsextension.cpp", "cpptoolsjsextension.h", "cpptoolsjsextension.cpp", "cpptoolsjsextension.h",
"cpptoolsplugin.cpp", "cpptoolsplugin.h", "cpptoolsplugin.cpp", "cpptoolsplugin.h",

View File

@@ -25,8 +25,23 @@
#pragma once #pragma once
#include "projectpart.h"
namespace CppTools { namespace CppTools {
enum class Language { C, Cxx }; enum class Language { C, Cxx };
class ProjectPartInfo {
public:
enum Hint {
NoHint,
IsFallbackMatch,
IsAmbiguousMatch
};
public:
ProjectPart::Ptr projectPart;
Hint hint;
};
} // namespace CppTools } // namespace CppTools

View File

@@ -47,7 +47,7 @@ namespace {
CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath) CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath)
{ {
if (const auto parser = BaseEditorDocumentParser::get(filePath)) if (const auto parser = BaseEditorDocumentParser::get(filePath))
return parser->projectPart(); return parser->projectPartInfo().projectPart;
return CppTools::ProjectPart::Ptr(); return CppTools::ProjectPart::Ptr();
} }

View File

@@ -25,12 +25,13 @@
#include "googletest.h" #include "googletest.h"
#include <cpptools/cpplanguage.h>
#include <cpptools/cppprojectpartchooser.h> #include <cpptools/cppprojectpartchooser.h>
#include <cpptools/cpptools_utils.h>
#include <cpptools/projectpart.h> #include <cpptools/projectpart.h>
using CppTools::Internal::ProjectPartChooser; using CppTools::Internal::ProjectPartChooser;
using CppTools::ProjectPart; using CppTools::ProjectPart;
using CppTools::ProjectPartInfo;
using CppTools::Language; using CppTools::Language;
using testing::Eq; using testing::Eq;
@@ -41,7 +42,7 @@ class ProjectPartChooser : public ::testing::Test
{ {
protected: protected:
void SetUp() override; void SetUp() override;
const ProjectPart::Ptr choose() const; const ProjectPartInfo choose() const;
static QList<ProjectPart::Ptr> createProjectPartsWithDifferentProjects(); static QList<ProjectPart::Ptr> createProjectPartsWithDifferentProjects();
static QList<ProjectPart::Ptr> createCAndCxxProjectParts(); static QList<ProjectPart::Ptr> createCAndCxxProjectParts();
@@ -65,7 +66,7 @@ TEST_F(ProjectPartChooser, ChooseManuallySet)
{ {
manuallySetProjectPart.reset(new ProjectPart); manuallySetProjectPart.reset(new ProjectPart);
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(manuallySetProjectPart)); ASSERT_THAT(chosen, Eq(manuallySetProjectPart));
} }
@@ -76,7 +77,7 @@ TEST_F(ProjectPartChooser, ForMultipleChoosePrevious)
projectPartsForFile += otherProjectPart; projectPartsForFile += otherProjectPart;
projectPartsForFile += currentProjectPart; projectPartsForFile += currentProjectPart;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(currentProjectPart)); ASSERT_THAT(chosen, Eq(currentProjectPart));
} }
@@ -88,7 +89,7 @@ TEST_F(ProjectPartChooser, ForMultipleChooseFromActiveProject)
projectPartsForFile += projectParts; projectPartsForFile += projectParts;
activeProject = secondProjectPart->project; activeProject = secondProjectPart->project;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(secondProjectPart)); ASSERT_THAT(chosen, Eq(secondProjectPart));
} }
@@ -102,7 +103,7 @@ TEST_F(ProjectPartChooser, ForMultiplePreferSelectedForBuilding)
projectPartsForFile += firstProjectPart; projectPartsForFile += firstProjectPart;
projectPartsForFile += secondProjectPart; projectPartsForFile += secondProjectPart;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(secondProjectPart)); ASSERT_THAT(chosen, Eq(secondProjectPart));
} }
@@ -114,7 +115,7 @@ TEST_F(ProjectPartChooser, ForMultipleFromDependenciesChooseFromActiveProject)
projectPartsFromDependenciesForFile += projectParts; projectPartsFromDependenciesForFile += projectParts;
activeProject = secondProjectPart->project; activeProject = secondProjectPart->project;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(secondProjectPart)); ASSERT_THAT(chosen, Eq(secondProjectPart));
} }
@@ -129,7 +130,7 @@ TEST_F(ProjectPartChooser, ForMultipleCheckIfActiveProjectChanged)
activeProject = secondProjectPart->project; activeProject = secondProjectPart->project;
projectHasChanged = true; projectHasChanged = true;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(secondProjectPart)); ASSERT_THAT(chosen, Eq(secondProjectPart));
} }
@@ -140,7 +141,7 @@ TEST_F(ProjectPartChooser, ForMultipleAndAmbigiousHeaderPreferCProjectPart)
projectPartsForFile = createCAndCxxProjectParts(); projectPartsForFile = createCAndCxxProjectParts();
const ProjectPart::Ptr cProjectPart = projectPartsForFile.at(0); const ProjectPart::Ptr cProjectPart = projectPartsForFile.at(0);
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(cProjectPart)); ASSERT_THAT(chosen, Eq(cProjectPart));
} }
@@ -151,16 +152,27 @@ TEST_F(ProjectPartChooser, ForMultipleAndAmbigiousHeaderPreferCxxProjectPart)
projectPartsForFile = createCAndCxxProjectParts(); projectPartsForFile = createCAndCxxProjectParts();
const ProjectPart::Ptr cxxProjectPart = projectPartsForFile.at(1); const ProjectPart::Ptr cxxProjectPart = projectPartsForFile.at(1);
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(cxxProjectPart)); 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 TEST_F(ProjectPartChooser, IfProjectIsGoneStickToPrevious) // Built-in Code Model
{ {
stickToPreviousProjectPart = true; stickToPreviousProjectPart = true;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(currentProjectPart)); ASSERT_THAT(chosen, Eq(currentProjectPart));
} }
@@ -170,7 +182,7 @@ TEST_F(ProjectPartChooser, IfProjectIsGoneDoNotStickToPrevious) // Clang Code Mo
currentProjectPart.clear(); currentProjectPart.clear();
stickToPreviousProjectPart = true; stickToPreviousProjectPart = true;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(ProjectPart::Ptr())); ASSERT_THAT(chosen, Eq(ProjectPart::Ptr()));
} }
@@ -180,7 +192,7 @@ TEST_F(ProjectPartChooser, ForMultipleChooseNewIfPreviousIsGone)
const ProjectPart::Ptr newProjectPart{new ProjectPart}; const ProjectPart::Ptr newProjectPart{new ProjectPart};
projectPartsForFile += newProjectPart; projectPartsForFile += newProjectPart;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(newProjectPart)); ASSERT_THAT(chosen, Eq(newProjectPart));
} }
@@ -190,7 +202,7 @@ TEST_F(ProjectPartChooser, FallbackToProjectPartFromDependencies)
const ProjectPart::Ptr fromDependencies{new ProjectPart}; const ProjectPart::Ptr fromDependencies{new ProjectPart};
projectPartsFromDependenciesForFile += fromDependencies; projectPartsFromDependenciesForFile += fromDependencies;
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(fromDependencies)); ASSERT_THAT(chosen, Eq(fromDependencies));
} }
@@ -199,11 +211,20 @@ TEST_F(ProjectPartChooser, FallbackToProjectPartFromModelManager)
{ {
fallbackProjectPart.reset(new ProjectPart); fallbackProjectPart.reset(new ProjectPart);
const ProjectPart::Ptr chosen = choose(); const ProjectPart::Ptr chosen = choose().projectPart;
ASSERT_THAT(chosen, Eq(fallbackProjectPart)); 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() void ProjectPartChooser::SetUp()
{ {
chooser.setFallbackProjectPart([&](){ chooser.setFallbackProjectPart([&](){
@@ -217,7 +238,7 @@ void ProjectPartChooser::SetUp()
}); });
} }
const ProjectPart::Ptr ProjectPartChooser::choose() const const ProjectPartInfo ProjectPartChooser::choose() const
{ {
return chooser.choose(filePath, return chooser.choose(filePath,
currentProjectPart, currentProjectPart,