Commit a137b08e authored by Ivan Donchevskii's avatar Ivan Donchevskii

CppEditor: refactor FollowSymbol

Create an interface to get the ability to use
another FollowSymbol implementation

Change-Id: I5802f62523ff3ee47b8a14e487adf43edcb6c9b1
Reviewed-by: Nikolai Kosjar's avatarNikolai Kosjar <nikolai.kosjar@qt.io>
parent 76d12dc2
......@@ -23,6 +23,7 @@ SOURCES += \
clangeditordocumentprocessor.cpp \
clangfixitoperation.cpp \
clangfixitoperationsextractor.cpp \
clangfollowsymbol.cpp \
clangfunctionhintmodel.cpp \
clanghighlightingmarksreporter.cpp \
clangmodelmanagersupport.cpp \
......@@ -54,6 +55,7 @@ HEADERS += \
clangeditordocumentprocessor.h \
clangfixitoperation.h \
clangfixitoperationsextractor.h \
clangfollowsymbol.h \
clangfunctionhintmodel.h \
clanghighlightingmarksreporter.h \
clangisdiagnosticrelatedtolocation.h \
......
......@@ -71,6 +71,8 @@ QtcPlugin {
"clangfixitoperation.h",
"clangfixitoperationsextractor.cpp",
"clangfixitoperationsextractor.h",
"clangfollowsymbol.cpp",
"clangfollowsymbol.h",
"clangfunctionhintmodel.cpp",
"clangfunctionhintmodel.h",
"clanghighlightingmarksreporter.cpp",
......
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "clangfollowsymbol.h"
#include "clangeditordocumentprocessor.h"
#include "texteditor/texteditor.h"
#include "texteditor/convenience.h"
namespace ClangCodeModel {
namespace Internal {
TextEditor::TextEditorWidget::Link ClangFollowSymbol::findLink(
const CppTools::CursorInEditor &data,
bool resolveTarget,
const CPlusPlus::Snapshot &,
const CPlusPlus::Document::Ptr &,
CppTools::SymbolFinder *,
bool)
{
Link link;
int lineNumber = 0, positionInBlock = 0;
QTextCursor cursor = TextEditor::Convenience::wordStartCursor(data.cursor());
TextEditor::Convenience::convertPosition(cursor.document(), cursor.position(), &lineNumber,
&positionInBlock);
const unsigned line = lineNumber;
const unsigned column = positionInBlock + 1;
if (!resolveTarget)
return link;
ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get(
data.filePath().toString());
if (!processor)
return link;
QFuture<CppTools::SymbolInfo> info
= processor->requestFollowSymbol(static_cast<int>(line),
static_cast<int>(column),
resolveTarget);
if (info.isCanceled())
return link;
while (!info.isFinished()) {
if (info.isCanceled())
return link;
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
CppTools::SymbolInfo result = info.result();
if (result.failedToFollow)
return link;
// We did not fail but the result is empty
if (result.fileName.isEmpty())
return link;
return Link(result.fileName, result.startLine, result.startColumn - 1);
}
} // namespace Internal
} // namespace ClangCodeModel
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <cpptools/followsymbolinterface.h>
namespace ClangCodeModel {
namespace Internal {
class ClangFollowSymbol : public CppTools::FollowSymbolInterface
{
public:
Link findLink(const CppTools::CursorInEditor &data,
bool resolveTarget,
const CPlusPlus::Snapshot &,
const CPlusPlus::Document::Ptr &,
CppTools::SymbolFinder *,
bool) override;
};
} // namespace Internal
} // namespace ClangCodeModel
......@@ -28,6 +28,7 @@
#include "clangconstants.h"
#include "clangeditordocumentprocessor.h"
#include "clangutils.h"
#include "clangfollowsymbol.h"
#include <coreplugin/editormanager/editormanager.h>
#include <cpptools/cppmodelmanager.h>
......@@ -52,6 +53,12 @@ using namespace ClangCodeModel::Internal;
static ModelManagerSupportClang *m_instance = 0;
static bool useClangFollowSymbol()
{
static bool use = qEnvironmentVariableIntValue("QTC_CLANG_FOLLOW_SYMBOL");
return use;
}
static CppTools::CppModelManager *cppModelManager()
{
return CppTools::CppModelManager::instance();
......@@ -63,6 +70,9 @@ ModelManagerSupportClang::ModelManagerSupportClang()
QTC_CHECK(!m_instance);
m_instance = this;
if (useClangFollowSymbol())
m_followSymbol.reset(new ClangFollowSymbol);
Core::EditorManager *editorManager = Core::EditorManager::instance();
connect(editorManager, &Core::EditorManager::editorOpened,
this, &ModelManagerSupportClang::onEditorOpened);
......@@ -96,6 +106,11 @@ CppTools::CppCompletionAssistProvider *ModelManagerSupportClang::completionAssis
return &m_completionAssistProvider;
}
CppTools::FollowSymbolInterface *ModelManagerSupportClang::followSymbolInterface()
{
return m_followSymbol.get();
}
CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::editorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument)
{
......
......@@ -33,6 +33,8 @@
#include <QObject>
#include <QScopedPointer>
#include <memory>
QT_BEGIN_NAMESPACE
class QMenu;
class QWidget;
......@@ -44,6 +46,8 @@ namespace TextEditor { class TextEditorWidget; }
namespace ClangCodeModel {
namespace Internal {
class ClangFollowSymbol;
class ModelManagerSupportClang:
public QObject,
public CppTools::ModelManagerSupport
......@@ -57,6 +61,7 @@ public:
CppTools::CppCompletionAssistProvider *completionAssistProvider() override;
CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor(
TextEditor::TextDocument *baseTextDocument) override;
CppTools::FollowSymbolInterface *followSymbolInterface() override;
IpcCommunicator &ipcCommunicator();
QString dummyUiHeaderOnDiskDirPath() const;
......@@ -100,6 +105,7 @@ private:
UiHeaderOnDiskManager m_uiHeaderOnDiskManager;
IpcCommunicator m_ipcCommunicator;
ClangCompletionAssistProvider m_completionAssistProvider;
std::unique_ptr<ClangFollowSymbol> m_followSymbol;
};
class ModelManagerSupportProviderClang : public CppTools::ModelManagerSupportProvider
......
......@@ -386,12 +386,6 @@ CppEditorDocument::cursorInfo(const CppTools::CursorInfoParams &params)
return processor()->cursorInfo(params);
}
QFuture<CppTools::SymbolInfo>
CppEditorDocument::requestFollowSymbol(int line, int column, bool resolveTarget)
{
return processor()->requestFollowSymbol(line, column, resolveTarget);
}
const MinimizableInfoBars &CppEditorDocument::minimizableInfoBars() const
{
return m_minimizableInfoBars;
......
......@@ -67,9 +67,6 @@ public:
ParseContextModel &parseContextModel();
QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams &params);
QFuture<CppTools::SymbolInfo> requestFollowSymbol(int line,
int column,
bool resolveTarget = true);
signals:
void codeWarningsUpdated(unsigned contentsRevision,
......
......@@ -93,6 +93,9 @@ private slots:
void test_FollowSymbolUnderCursor_data();
void test_FollowSymbolUnderCursor();
void test_FollowSymbolUnderCursor_QTCREATORBUG7903_data();
void test_FollowSymbolUnderCursor_QTCREATORBUG7903();
void test_FollowSymbolUnderCursor_followCall_data();
void test_FollowSymbolUnderCursor_followCall();
......
......@@ -129,8 +129,8 @@ public:
CppLocalRenaming m_localRenaming;
CppUseSelectionsUpdater m_useSelectionsUpdater;
QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
CppSelectionChanger m_cppSelectionChanger;
FollowSymbolUnderCursor m_builtinFollowSymbol;
CppRefactoringEngine m_builtinRefactoringEngine;
};
......@@ -141,7 +141,6 @@ CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
, m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
, m_localRenaming(q)
, m_useSelectionsUpdater(q)
, m_followSymbolUnderCursor(new FollowSymbolUnderCursor(q))
, m_cppSelectionChanger()
{}
......@@ -647,12 +646,23 @@ CppEditorWidget::Link CppEditorWidget::findLinkAt(const QTextCursor &cursor,
if (!d->m_modelManager)
return Link();
return d->m_followSymbolUnderCursor->findLink(cursor,
resolveTarget,
d->m_modelManager->snapshot(),
d->m_lastSemanticInfo.doc,
d->m_modelManager->symbolFinder(),
inNextSplit);
const Utils::FileName &filePath = textDocument()->filePath();
if (!resolveTarget) {
// TODO: get that part also from clang
return d->m_builtinFollowSymbol.findLink(CppTools::CursorInEditor{cursor, filePath, this},
resolveTarget,
d->m_modelManager->snapshot(),
d->m_lastSemanticInfo.doc,
d->m_modelManager->symbolFinder(),
inNextSplit);
}
return followSymbolInterface()->findLink(CppTools::CursorInEditor{cursor, filePath, this},
resolveTarget,
d->m_modelManager->snapshot(),
d->m_lastSemanticInfo.doc,
d->m_modelManager->symbolFinder(),
inNextSplit);
}
unsigned CppEditorWidget::documentRevision() const
......@@ -687,6 +697,14 @@ RefactoringEngineInterface *CppEditorWidget::refactoringEngine() const
: static_cast<RefactoringEngineInterface *>(&d->m_builtinRefactoringEngine);
}
CppTools::FollowSymbolInterface *CppEditorWidget::followSymbolInterface() const
{
CppTools::FollowSymbolInterface *followSymbol
= CppTools::CppModelManager::instance()->followSymbolInterface();
return followSymbol ? followSymbol
: static_cast<CppTools::FollowSymbolInterface *>(&d->m_builtinFollowSymbol);
}
bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const
{
return d->m_lastSemanticInfo.doc && d->m_lastSemanticInfo.revision == documentRevision()
......@@ -973,11 +991,6 @@ void CppEditorWidget::applyDeclDefLinkChanges(bool jumpToMatch)
updateFunctionDeclDefLink();
}
FollowSymbolUnderCursor *CppEditorWidget::followSymbolUnderCursorDelegate()
{
return d->m_followSymbolUnderCursor.data();
}
void CppEditorWidget::encourageApply()
{
if (d->m_localRenaming.encourageApply())
......
......@@ -32,6 +32,7 @@
namespace CppTools {
class CppEditorOutline;
class RefactoringEngineInterface;
class FollowSymbolInterface;
class SemanticInfo;
class ProjectPart;
}
......@@ -42,7 +43,6 @@ namespace Internal {
class CppEditorDocument;
class CppEditorWidgetPrivate;
class FollowSymbolUnderCursor;
class FunctionDeclDefLink;
class CppEditorWidget : public TextEditor::TextEditorWidget
......@@ -67,8 +67,6 @@ public:
TextEditor::AssistKind kind,
TextEditor::AssistReason reason) const override;
FollowSymbolUnderCursor *followSymbolUnderCursorDelegate(); // exposed for tests
void encourageApply() override;
void paste() override;
......@@ -89,6 +87,8 @@ public:
static bool isWidgetHighlighted(QWidget *widget);
void updateSemanticInfo();
CppTools::FollowSymbolInterface *followSymbolInterface() const;
protected:
bool event(QEvent *e) override;
void contextMenuEvent(QContextMenuEvent *) override;
......
......@@ -55,12 +55,6 @@ typedef TextEditorWidget::Link Link;
namespace {
static bool useClangFollowSymbol()
{
static bool use = qEnvironmentVariableIntValue("QTC_CLANG_FOLLOW_SYMBOL");
return use;
}
class VirtualFunctionHelper {
public:
VirtualFunctionHelper(TypeOfExpression &typeOfExpression,
......@@ -305,9 +299,9 @@ inline LookupItem skipForwardDeclarations(const QList<LookupItem> &resolvedSymbo
return result;
}
CppEditorWidget::Link attemptFuncDeclDef(const QTextCursor &cursor,
CppEditorWidget *, Snapshot snapshot, const Document::Ptr &document,
SymbolFinder *symbolFinder)
CppEditorWidget::Link attemptFuncDeclDef(const QTextCursor &cursor, Snapshot snapshot,
const Document::Ptr &document,
SymbolFinder *symbolFinder)
{
Link result;
QTC_ASSERT(document, return result);
......@@ -467,15 +461,9 @@ QString expressionUnderCursorAsString(const QTextCursor &textCursor,
} // anonymous namespace
FollowSymbolUnderCursor::FollowSymbolUnderCursor(CppEditorWidget *widget)
: m_widget(widget)
, m_virtualFunctionAssistProvider(new VirtualFunctionAssistProvider)
{
}
FollowSymbolUnderCursor::~FollowSymbolUnderCursor()
FollowSymbolUnderCursor::FollowSymbolUnderCursor()
: m_virtualFunctionAssistProvider(new VirtualFunctionAssistProvider)
{
delete m_virtualFunctionAssistProvider;
}
static int skipMatchingParentheses(const Tokens &tokens, int idx, int initialDepth)
......@@ -495,61 +483,28 @@ static int skipMatchingParentheses(const Tokens &tokens, int idx, int initialDep
return j;
}
bool FollowSymbolUnderCursor::processorFollowSymbol(uint line, uint column, bool resolveTarget,
Link &linkResult)
{
if (!useClangFollowSymbol())
return false;
CppEditorDocument* editorDocument = m_widget->cppEditorDocument();
if (!editorDocument)
return false;
QFuture<CppTools::SymbolInfo> info
= editorDocument->requestFollowSymbol(static_cast<int>(line),
static_cast<int>(column),
resolveTarget);
if (info.isCanceled())
return false;
while (!info.isFinished()) {
if (info.isCanceled())
return false;
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
CppTools::SymbolInfo result = info.result();
// Try again with built-in code model (happens with some includes)
if (result.failedToFollow)
return false;
// We did not fail but the result is empty
if (result.fileName.isEmpty())
return true;
linkResult = Link(result.fileName, result.startLine, result.startColumn - 1);
return true;
}
TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &cursor,
bool resolveTarget, const Snapshot &theSnapshot, const Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder, bool inNextSplit)
Link FollowSymbolUnderCursor::findLink(
const CppTools::CursorInEditor &data,
bool resolveTarget,
const Snapshot &theSnapshot,
const Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder,
bool inNextSplit)
{
Link link;
int lineNumber = 0, positionInBlock = 0;
m_widget->convertPosition(cursor.position(), &lineNumber, &positionInBlock);
QTextCursor cursor = data.cursor();
QTextDocument *document = cursor.document();
TextEditor::Convenience::convertPosition(document, cursor.position(), &lineNumber,
&positionInBlock);
const unsigned line = lineNumber;
const unsigned column = positionInBlock + 1;
if (resolveTarget && processorFollowSymbol(line, column, resolveTarget, link))
return link;
Snapshot snapshot = theSnapshot;
// Move to end of identifier
QTextCursor tc = cursor;
QTextDocument *document = m_widget->document();
QChar ch = document->characterAt(tc.position());
while (CppTools::isValidIdentifierChar(ch)) {
tc.movePosition(QTextCursor::NextCharacter);
......@@ -564,7 +519,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
while (document->characterAt(pos).isSpace())
++pos;
if (document->characterAt(pos) == QLatin1Char('(')) {
link = attemptFuncDeclDef(cursor, m_widget, snapshot, documentFromSemanticInfo,
link = attemptFuncDeclDef(cursor, snapshot, documentFromSemanticInfo,
symbolFinder);
if (link.hasValidLinkText())
return link;
......@@ -636,7 +591,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
&& unsigned(positionInBlock) <= tk.utf16charsEnd()) {
cursorRegionReached = true;
if (tk.is(T_OPERATOR)) {
link = attemptFuncDeclDef(cursor, m_widget, theSnapshot,
link = attemptFuncDeclDef(cursor, theSnapshot,
documentFromSemanticInfo, symbolFinder);
if (link.hasValidLinkText())
return link;
......@@ -644,7 +599,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
QTextCursor c = cursor;
c.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor,
positionInBlock - tokens.at(i - 1).utf16charsBegin());
link = attemptFuncDeclDef(c, m_widget, theSnapshot, documentFromSemanticInfo,
link = attemptFuncDeclDef(c, theSnapshot, documentFromSemanticInfo,
symbolFinder);
if (link.hasValidLinkText())
return link;
......@@ -655,8 +610,11 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
}
}
CppEditorWidget *editorWidget = static_cast<CppEditorWidget *>(data.editorWidget());
if (!editorWidget)
return link;
// Now we prefer the doc from the snapshot with macros expanded.
Document::Ptr doc = snapshot.document(m_widget->textDocument()->filePath());
Document::Ptr doc = snapshot.document(editorWidget->textDocument()->filePath());
if (!doc) {
doc = documentFromSemanticInfo;
if (!doc)
......@@ -705,7 +663,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
} else if (const Document::MacroUse *use = doc->findMacroUseAt(endOfToken - 1)) {
const QString fileName = use->macro().fileName();
if (fileName == CppModelManager::editorConfigurationFileName()) {
m_widget->showPreProcessorWidget();
editorWidget->showPreProcessorWidget();
} else if (fileName != CppModelManager::configurationFileName()) {
const Macro &macro = use->macro();
link.targetFileName = macro.fileName();
......@@ -739,7 +697,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
if (Symbol *d = r.declaration()) {
if (d->isDeclaration() || d->isFunction()) {
const QString fileName = QString::fromUtf8(d->fileName(), d->fileNameLength());
if (m_widget->textDocument()->filePath().toString() == fileName) {
if (editorWidget->textDocument()->filePath().toString() == fileName) {
if (unsigned(lineNumber) == d->line()
&& unsigned(positionInBlock) >= d->column()) { // TODO: check the end
result = r; // take the symbol under cursor.
......@@ -748,7 +706,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
}
} else if (d->isUsingDeclaration()) {
int tokenBeginLineNumber = 0, tokenBeginColumnNumber = 0;
m_widget->convertPosition(beginOfToken, &tokenBeginLineNumber,
editorWidget->convertPosition(beginOfToken, &tokenBeginLineNumber,
&tokenBeginColumnNumber);
if (unsigned(tokenBeginLineNumber) > d->line()
|| (unsigned(tokenBeginLineNumber) == d->line()
......@@ -778,7 +736,7 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
params.openInNextSplit = inNextSplit;
if (m_virtualFunctionAssistProvider->configure(params)) {
m_widget->invokeAssist(FollowSymbol, m_virtualFunctionAssistProvider);
editorWidget->invokeAssist(FollowSymbol, m_virtualFunctionAssistProvider.data());
m_virtualFunctionAssistProvider->clearParams();
}
......@@ -827,12 +785,13 @@ TextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &curs
return Link();
}
VirtualFunctionAssistProvider *FollowSymbolUnderCursor::virtualFunctionAssistProvider()
QSharedPointer<VirtualFunctionAssistProvider> FollowSymbolUnderCursor::virtualFunctionAssistProvider()
{
return m_virtualFunctionAssistProvider;
}
void FollowSymbolUnderCursor::setVirtualFunctionAssistProvider(VirtualFunctionAssistProvider *provider)
void FollowSymbolUnderCursor::setVirtualFunctionAssistProvider(
const QSharedPointer<VirtualFunctionAssistProvider> &provider)
{
m_virtualFunctionAssistProvider = provider;
}
......@@ -25,44 +25,31 @@
#pragma once
#include <cplusplus/CppDocument.h>
#include <texteditor/texteditor.h>
QT_BEGIN_NAMESPACE
class QTextCursor;
QT_END_NAMESPACE
namespace CppTools { class SymbolFinder; }
#include <cpptools/followsymbolinterface.h>
namespace CppEditor {
namespace Internal {
class CppEditorWidget;
class VirtualFunctionAssistProvider;
class FollowSymbolUnderCursor
class FollowSymbolUnderCursor : public CppTools::FollowSymbolInterface
{
public:
typedef TextEditor::TextEditorWidget::Link Link;
FollowSymbolUnderCursor(CppEditorWidget *widget);
~FollowSymbolUnderCursor();
FollowSymbolUnderCursor();
Link findLink(const QTextCursor &cursor, bool resolveTarget,
Link findLink(const CppTools::CursorInEditor &data,
bool resolveTarget,
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
CppTools::SymbolFinder *symbolFinder, bool inNextSplit);
CppTools::SymbolFinder *symbolFinder,
bool inNextSplit) override;
VirtualFunctionAssistProvider *virtualFunctionAssistProvider();
void setVirtualFunctionAssistProvider(VirtualFunctionAssistProvider *provider);
QSharedPointer<VirtualFunctionAssistProvider> virtualFunctionAssistProvider();
void setVirtualFunctionAssistProvider(
const QSharedPointer<VirtualFunctionAssistProvider> &provider);
private:
// Try to follow symbol with clang processor
// Returns false if it has failed and we want to try again with built-in one
bool processorFollowSymbol(uint line, uint column, bool resolveTarget,
Link &result);
CppEditorWidget *m_widget;
VirtualFunctionAssistProvider *m_virtualFunctionAssistProvider;
QSharedPointer<VirtualFunctionAssistProvider> m_virtualFunctionAssistProvider;
};
} // namespace Internal
......
......@@ -33,6 +33,7 @@
#include "cppvirtualfunctionproposalitem.h"
#include <cpptools/cpptoolstestcase.h>
#include <cpptools/cppmodelmanager.h>
#include <texteditor/codeassist/genericproposalmodel.h>
#include <texteditor/codeassist/iassistprocessor.h>
......@@ -326,19 +327,37 @@ F2TestCase::F2TestCase(CppEditorAction action,
switch (action) {
case FollowSymbolUnderCursorAction: {
CppEditorWidget *widget = initialTestFile->m_editorWidget;
FollowSymbolUnderCursor *delegate = widget->followSymbolUnderCursorDelegate();
VirtualFunctionAssistProvider *original = delegate->virtualFunctionAssistProvider();
FollowSymbolInterface* delegate = widget->followSymbolInterface();
if (!delegate)
QFAIL("No follow symbol interface");
auto* builtinFollowSymbol = dynamic_cast<FollowSymbolUnderCursor *>(delegate);
if (!builtinFollowSymbol) {
if (filePaths.size() > 1)
QSKIP("Clang FollowSymbol does not currently support multiple files (except cpp+header)");
const QString curTestName = QLatin1String(QTest::currentTestFunction());
if (curTestName == "test_FollowSymbolUnderCursor_QObject_connect"
|| curTestName == "test_FollowSymbolUnderCursor_virtualFunctionCall"
|| curTestName == "test_FollowSymbolUnderCursor_QTCREATORBUG7903") {
QSKIP((curTestName + " is not supported by Clang FollowSymbol").toLatin1());
}
initialTestFile->m_editorWidget->openLinkUnderCursor();
break;
}
QSharedPointer<VirtualFunctionAssistProvider> original
= builtinFollowSymbol->virtualFunctionAssistProvider();
// Set test provider, run and get results
QScopedPointer<VirtualFunctionTestAssistProvider> testProvider(
QSharedPointer<VirtualFunctionTestAssistProvider> testProvider(
new VirtualFunctionTestAssistProvider(widget));
delegate->setVirtualFunctionAssistProvider(testProvider.data());
builtinFollowSymbol->setVirtualFunctionAssistProvider(testProvider);
initialTestFile->m_editorWidget->openLinkUnderCursor();
immediateVirtualSymbolResults = testProvider->m_immediateItems;
finalVirtualSymbolResults = testProvider->m_finalItems;
// Restore original test provider
delegate->setVirtualFunctionAssistProvider(original);
builtinFollowSymbol->setVirtualFunctionAssistProvider(original);
break;
}
case SwitchBetweenMethodDeclarationDefinitionAction:
......@@ -870,41 +889,6 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_data()
"@Container<int> container;\n"
);
QTest::newRow("using_QTCREATORBUG7903_globalNamespace") << _(
"namespace NS {\n"