CppTools: Remove processEvents call from follow symbol

processEvents is a bad way of dealing with asynchronous
requests. Use QFutureWatcher for that purpose.

Change-Id: I3839cb9db80a6d391f6af1178e96986a325b7b99
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-02-21 11:58:16 +01:00
parent d471006d81
commit 08d1274ccc
22 changed files with 197 additions and 126 deletions

View File

@@ -28,6 +28,8 @@
#include <QString> #include <QString>
#include <qmetatype.h> #include <qmetatype.h>
#include <functional>
namespace Utils { namespace Utils {
struct Link struct Link
@@ -57,6 +59,8 @@ struct Link
int targetColumn; int targetColumn;
}; };
using ProcessLinkCallback = std::function<void(const Link &)>;
} // namespace Utils } // namespace Utils
Q_DECLARE_METATYPE(Utils::Link) Q_DECLARE_METATYPE(Utils::Link)

View File

@@ -93,12 +93,13 @@ static Utils::Link linkAtCursor(QTextCursor cursor, const QString &filePath, uin
return Link(); return Link();
} }
Utils::Link ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data, void ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
bool resolveTarget, ::Utils::ProcessLinkCallback &&processLinkCallback,
const CPlusPlus::Snapshot &snapshot, bool resolveTarget,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Snapshot &snapshot,
CppTools::SymbolFinder *symbolFinder, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
bool inNextSplit) CppTools::SymbolFinder *symbolFinder,
bool inNextSplit)
{ {
int lineNumber = 0, positionInBlock = 0; int lineNumber = 0, positionInBlock = 0;
QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor()); QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor());
@@ -111,34 +112,40 @@ Utils::Link ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get( ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get(
data.filePath().toString()); data.filePath().toString());
if (!processor) if (!processor)
return Link(); return processLinkCallback(Utils::Link());
if (!resolveTarget) if (!resolveTarget) {
return linkAtCursor(cursor, data.filePath().toString(), line, column, processor); processLinkCallback(linkAtCursor(cursor, data.filePath().toString(), line, column,
processor));
return;
}
QFuture<CppTools::SymbolInfo> info QFuture<CppTools::SymbolInfo> infoFuture
= processor->requestFollowSymbol(static_cast<int>(line), = processor->requestFollowSymbol(static_cast<int>(line),
static_cast<int>(column)); static_cast<int>(column));
if (info.isCanceled()) if (infoFuture.isCanceled())
return Link(); return processLinkCallback(Utils::Link());
while (!info.isFinished()) { QObject::connect(&m_watcher, &FutureSymbolWatcher::finished,
if (info.isCanceled()) [=, watcher=&m_watcher, callback=std::move(processLinkCallback)]() mutable {
return Link(); CppTools::SymbolInfo result = watcher->result();
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); // We did not fail but the result is empty
} if (result.fileName.isEmpty()) {
CppTools::SymbolInfo result = info.result(); const CppTools::RefactoringEngineInterface &refactoringEngine
= *CppTools::CppModelManager::instance();
refactoringEngine.globalFollowSymbol(data,
std::move(callback),
snapshot,
documentFromSemanticInfo,
symbolFinder,
inNextSplit);
} else {
callback(Link(result.fileName, result.startLine, result.startColumn - 1));
}
});
// We did not fail but the result is empty m_watcher.setFuture(infoFuture);
if (result.fileName.isEmpty()) {
const CppTools::RefactoringEngineInterface &refactoringEngine
= *CppTools::CppModelManager::instance();
return refactoringEngine.globalFollowSymbol(data, snapshot, documentFromSemanticInfo,
symbolFinder, inNextSplit);
}
return Link(result.fileName, result.startLine, result.startColumn - 1);
} }
} // namespace Internal } // namespace Internal

View File

@@ -26,6 +26,9 @@
#pragma once #pragma once
#include <cpptools/followsymbolinterface.h> #include <cpptools/followsymbolinterface.h>
#include <cpptools/cppsymbolinfo.h>
#include <QFutureWatcher>
namespace ClangCodeModel { namespace ClangCodeModel {
namespace Internal { namespace Internal {
@@ -33,12 +36,16 @@ namespace Internal {
class ClangFollowSymbol : public CppTools::FollowSymbolInterface class ClangFollowSymbol : public CppTools::FollowSymbolInterface
{ {
public: public:
Link findLink(const CppTools::CursorInEditor &data, void findLink(const CppTools::CursorInEditor &data,
::Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget, bool resolveTarget,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
CppTools::SymbolFinder *symbolFinder, CppTools::SymbolFinder *symbolFinder,
bool inNextSplit) override; bool inNextSplit) override;
private:
using FutureSymbolWatcher = QFutureWatcher<CppTools::SymbolInfo>;
FutureSymbolWatcher m_watcher;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -46,11 +46,13 @@ public:
void globalRename(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&, void globalRename(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&,
const QString &) override {} const QString &) override {}
void findUsages(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&) const override {} void findUsages(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&) const override {}
Link globalFollowSymbol(const CppTools::CursorInEditor &, const CPlusPlus::Snapshot &, void globalFollowSymbol(const CppTools::CursorInEditor &,
const CPlusPlus::Document::Ptr &, CppTools::SymbolFinder *, ::Utils::ProcessLinkCallback &&,
const CPlusPlus::Snapshot &,
const CPlusPlus::Document::Ptr &,
CppTools::SymbolFinder *,
bool) const override bool) const override
{ {
return Link();
} }
private: private:

View File

@@ -123,11 +123,12 @@ void RefactoringEngine::findUsages(const CppTools::CursorInEditor &data,
showUsagesCallback(locationsAt(data)); showUsagesCallback(locationsAt(data));
} }
RefactoringEngine::Link RefactoringEngine::globalFollowSymbol(const CppTools::CursorInEditor &data, void RefactoringEngine::globalFollowSymbol(const CppTools::CursorInEditor &data,
const CPlusPlus::Snapshot &, Utils::ProcessLinkCallback &&processLinkCallback,
const CPlusPlus::Document::Ptr &, const CPlusPlus::Snapshot &,
CppTools::SymbolFinder *, const CPlusPlus::Document::Ptr &,
bool) const CppTools::SymbolFinder *,
bool) const
{ {
// TODO: replace that with specific followSymbol query // TODO: replace that with specific followSymbol query
const CppTools::Usages usages = locationsAt(data); const CppTools::Usages usages = locationsAt(data);
@@ -138,7 +139,7 @@ RefactoringEngine::Link RefactoringEngine::globalFollowSymbol(const CppTools::Cu
return true; return true;
}); });
return Link(usage.path, usage.line, usage.column); processLinkCallback(Link(usage.path, usage.line, usage.column));
} }
bool RefactoringEngine::isRefactoringEngineAvailable() const bool RefactoringEngine::isRefactoringEngineAvailable() const

View File

@@ -57,7 +57,8 @@ public:
const QString &) override; const QString &) override;
void findUsages(const CppTools::CursorInEditor &data, void findUsages(const CppTools::CursorInEditor &data,
CppTools::UsagesCallback &&showUsagesCallback) const override; CppTools::UsagesCallback &&showUsagesCallback) const override;
Link globalFollowSymbol(const CppTools::CursorInEditor &data, void globalFollowSymbol(const CppTools::CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
const CPlusPlus::Snapshot &, const CPlusPlus::Snapshot &,
const CPlusPlus::Document::Ptr &, const CPlusPlus::Document::Ptr &,
CppTools::SymbolFinder *, CppTools::SymbolFinder *,

View File

@@ -117,7 +117,10 @@ public:
private: private:
bool save(const QString &fileName = QString()); bool save(const QString &fileName = QString());
Utils::Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true, bool inNextSplit = false) override; void findLinkAt(const QTextCursor &cursor,
Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget = true,
bool inNextSplit = false) override;
void contextMenuEvent(QContextMenuEvent *e) override; void contextMenuEvent(QContextMenuEvent *e) override;
}; };
@@ -136,8 +139,10 @@ static bool isValidFileNameChar(const QChar &c)
|| c == QLatin1Char('\\'); || c == QLatin1Char('\\');
} }
Utils::Link CMakeEditorWidget::findLinkAt(const QTextCursor &cursor, void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
bool/* resolveTarget*/, bool /*inNextSplit*/) Utils::ProcessLinkCallback &&processLinkCallback,
bool/* resolveTarget*/,
bool /*inNextSplit*/)
{ {
Utils::Link link; Utils::Link link;
@@ -149,7 +154,7 @@ Utils::Link CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
// check if the current position is commented out // check if the current position is commented out
const int hashPos = block.indexOf(QLatin1Char('#')); const int hashPos = block.indexOf(QLatin1Char('#'));
if (hashPos >= 0 && hashPos < positionInBlock) if (hashPos >= 0 && hashPos < positionInBlock)
return link; return processLinkCallback(link);
// find the beginning of a filename // find the beginning of a filename
QString buffer; QString buffer;
@@ -177,7 +182,7 @@ Utils::Link CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
} }
if (buffer.isEmpty()) if (buffer.isEmpty())
return link; return processLinkCallback(link);
// TODO: Resolve variables // TODO: Resolve variables
@@ -191,13 +196,13 @@ Utils::Link CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
if (QFileInfo::exists(subProject)) if (QFileInfo::exists(subProject))
fileName = subProject; fileName = subProject;
else else
return link; return processLinkCallback(link);
} }
link.targetFileName = fileName; link.targetFileName = fileName;
link.linkTextStart = cursor.position() - positionInBlock + beginPos + 1; link.linkTextStart = cursor.position() - positionInBlock + beginPos + 1;
link.linkTextEnd = cursor.position() - positionInBlock + endPos; link.linkTextEnd = cursor.position() - positionInBlock + endPos;
} }
return link; processLinkCallback(link);
} }
static TextDocument *createCMakeDocument() static TextDocument *createCMakeDocument()

View File

@@ -718,21 +718,23 @@ void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit)
openLink(symbolLink, inNextSplit != alwaysOpenLinksInNextSplit()); openLink(symbolLink, inNextSplit != alwaysOpenLinksInNextSplit());
} }
Utils::Link CppEditorWidget::findLinkAt(const QTextCursor &cursor, void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
bool resolveTarget, Utils::ProcessLinkCallback &&processLinkCallback,
bool inNextSplit) bool resolveTarget,
bool inNextSplit)
{ {
if (!d->m_modelManager) if (!d->m_modelManager)
return Utils::Link(); return processLinkCallback(Utils::Link());
const Utils::FileName &filePath = textDocument()->filePath(); const Utils::FileName &filePath = textDocument()->filePath();
return followSymbolInterface().findLink(CppTools::CursorInEditor{cursor, filePath, this}, followSymbolInterface().findLink(CppTools::CursorInEditor{cursor, filePath, this},
resolveTarget, std::move(processLinkCallback),
d->m_modelManager->snapshot(), resolveTarget,
d->m_lastSemanticInfo.doc, d->m_modelManager->snapshot(),
d->m_modelManager->symbolFinder(), d->m_lastSemanticInfo.doc,
inNextSplit); d->m_modelManager->symbolFinder(),
inNextSplit);
} }
unsigned CppEditorWidget::documentRevision() const unsigned CppEditorWidget::documentRevision() const

View File

@@ -100,8 +100,10 @@ protected:
void keyPressEvent(QKeyEvent *e) override; void keyPressEvent(QKeyEvent *e) override;
bool handleStringSplitting(QKeyEvent *e) const; bool handleStringSplitting(QKeyEvent *e) const;
Utils::Link findLinkAt(const QTextCursor &, bool resolveTarget = true, void findLinkAt(const QTextCursor &cursor,
bool inNextSplit = false) override; Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget = true,
bool inNextSplit = false) override;
void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker) override; void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker) override;

View File

@@ -480,8 +480,9 @@ static int skipMatchingParentheses(const Tokens &tokens, int idx, int initialDep
return j; return j;
} }
Link FollowSymbolUnderCursor::findLink( void FollowSymbolUnderCursor::findLink(
const CppTools::CursorInEditor &data, const CppTools::CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget, bool resolveTarget,
const Snapshot &theSnapshot, const Snapshot &theSnapshot,
const Document::Ptr &documentFromSemanticInfo, const Document::Ptr &documentFromSemanticInfo,
@@ -518,7 +519,7 @@ Link FollowSymbolUnderCursor::findLink(
link = attemptFuncDeclDef(cursor, snapshot, documentFromSemanticInfo, link = attemptFuncDeclDef(cursor, snapshot, documentFromSemanticInfo,
symbolFinder); symbolFinder);
if (link.hasValidLinkText()) if (link.hasValidLinkText())
return link; return processLinkCallback(link);
} }
} }
@@ -590,7 +591,7 @@ Link FollowSymbolUnderCursor::findLink(
link = attemptFuncDeclDef(cursor, theSnapshot, link = attemptFuncDeclDef(cursor, theSnapshot,
documentFromSemanticInfo, symbolFinder); documentFromSemanticInfo, symbolFinder);
if (link.hasValidLinkText()) if (link.hasValidLinkText())
return link; return processLinkCallback(link);
} else if (tk.isOperator() && i > 0 && tokens.at(i - 1).is(T_OPERATOR)) { } else if (tk.isOperator() && i > 0 && tokens.at(i - 1).is(T_OPERATOR)) {
QTextCursor c = cursor; QTextCursor c = cursor;
c.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, c.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor,
@@ -598,7 +599,7 @@ Link FollowSymbolUnderCursor::findLink(
link = attemptFuncDeclDef(c, theSnapshot, documentFromSemanticInfo, link = attemptFuncDeclDef(c, theSnapshot, documentFromSemanticInfo,
symbolFinder); symbolFinder);
if (link.hasValidLinkText()) if (link.hasValidLinkText())
return link; return processLinkCallback(link);
} }
} else if (cursorRegionReached) { } else if (cursorRegionReached) {
break; break;
@@ -608,13 +609,14 @@ Link FollowSymbolUnderCursor::findLink(
CppEditorWidgetInterface *editorWidget = data.editorWidget(); CppEditorWidgetInterface *editorWidget = data.editorWidget();
if (!editorWidget) if (!editorWidget)
return link; return processLinkCallback(link);
// Now we prefer the doc from the snapshot with macros expanded. // Now we prefer the doc from the snapshot with macros expanded.
Document::Ptr doc = snapshot.document(data.filePath()); Document::Ptr doc = snapshot.document(data.filePath());
if (!doc) { if (!doc) {
doc = documentFromSemanticInfo; doc = documentFromSemanticInfo;
if (!doc) if (!doc)
return link; return processLinkCallback(link);
} }
if (!recognizedQtMethod) { if (!recognizedQtMethod) {
@@ -638,13 +640,14 @@ Link FollowSymbolUnderCursor::findLink(
link.targetFileName = incl.resolvedFileName(); link.targetFileName = incl.resolvedFileName();
link.linkTextStart = beginOfToken + 1; link.linkTextStart = beginOfToken + 1;
link.linkTextEnd = endOfToken - 1; link.linkTextEnd = endOfToken - 1;
return link; processLinkCallback(link);
return;
} }
} }
} }
if (tk.isNot(T_IDENTIFIER) && !tk.isQtKeyword()) if (tk.isNot(T_IDENTIFIER) && !tk.isQtKeyword())
return link; return processLinkCallback(link);
tc.setPosition(endOfToken); tc.setPosition(endOfToken);
} }
@@ -655,7 +658,7 @@ Link FollowSymbolUnderCursor::findLink(
QTextCursor macroCursor = cursor; QTextCursor macroCursor = cursor;
const QByteArray name = CppTools::identifierUnderCursor(&macroCursor).toUtf8(); const QByteArray name = CppTools::identifierUnderCursor(&macroCursor).toUtf8();
if (macro->name() == name) if (macro->name() == name)
return link; //already on definition! return processLinkCallback(link); //already on definition!
} else if (const Document::MacroUse *use = doc->findMacroUseAt(endOfToken - 1)) { } else if (const Document::MacroUse *use = doc->findMacroUseAt(endOfToken - 1)) {
const QString fileName = use->macro().fileName(); const QString fileName = use->macro().fileName();
if (fileName == CppModelManager::editorConfigurationFileName()) { if (fileName == CppModelManager::editorConfigurationFileName()) {
@@ -667,13 +670,14 @@ Link FollowSymbolUnderCursor::findLink(
link.linkTextStart = use->utf16charsBegin(); link.linkTextStart = use->utf16charsBegin();
link.linkTextEnd = use->utf16charsEnd(); link.linkTextEnd = use->utf16charsEnd();
} }
return link; processLinkCallback(link);
return;
} }
// Find the last symbol up to the cursor position // Find the last symbol up to the cursor position
Scope *scope = doc->scopeAt(line, column); Scope *scope = doc->scopeAt(line, column);
if (!scope) if (!scope)
return link; return processLinkCallback(link);
// Evaluate the type of the expression under the cursor // Evaluate the type of the expression under the cursor
QTC_CHECK(document == tc.document()); QTC_CHECK(document == tc.document());
@@ -741,7 +745,8 @@ Link FollowSymbolUnderCursor::findLink(
Link link; Link link;
link.linkTextStart = beginOfToken; link.linkTextStart = beginOfToken;
link.linkTextEnd = endOfToken; link.linkTextEnd = endOfToken;
return link; processLinkCallback(link);
return;
} }
Symbol *lastVisibleSymbol = doc->lastVisibleSymbolAt(line, column); Symbol *lastVisibleSymbol = doc->lastVisibleSymbolAt(line, column);
@@ -765,7 +770,8 @@ Link FollowSymbolUnderCursor::findLink(
link = (def ? def : symbol)->toLink(); link = (def ? def : symbol)->toLink();
link.linkTextStart = beginOfToken; link.linkTextStart = beginOfToken;
link.linkTextEnd = endOfToken; link.linkTextEnd = endOfToken;
return link; processLinkCallback(link);
return;
} }
} }
@@ -776,10 +782,11 @@ Link FollowSymbolUnderCursor::findLink(
if (link.hasValidTarget()) { if (link.hasValidTarget()) {
link.linkTextStart = macroCursor.selectionStart(); link.linkTextStart = macroCursor.selectionStart();
link.linkTextEnd = macroCursor.selectionEnd(); link.linkTextEnd = macroCursor.selectionEnd();
return link; processLinkCallback(link);
return;
} }
return Link(); processLinkCallback(Link());
} }
QSharedPointer<VirtualFunctionAssistProvider> FollowSymbolUnderCursor::virtualFunctionAssistProvider() QSharedPointer<VirtualFunctionAssistProvider> FollowSymbolUnderCursor::virtualFunctionAssistProvider()

View File

@@ -36,7 +36,8 @@ class CPPTOOLS_EXPORT FollowSymbolUnderCursor : public CppTools::FollowSymbolInt
public: public:
FollowSymbolUnderCursor(); FollowSymbolUnderCursor();
Link findLink(const CppTools::CursorInEditor &data, void findLink(const CppTools::CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget, bool resolveTarget,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,

View File

@@ -327,17 +327,18 @@ void CppModelManager::findUsages(const CppTools::CursorInEditor &data,
engine->findUsages(data, std::move(showUsagesCallback)); engine->findUsages(data, std::move(showUsagesCallback));
} }
CppModelManager::Link CppModelManager::globalFollowSymbol( void CppModelManager::globalFollowSymbol(
const CursorInEditor &data, const CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder, SymbolFinder *symbolFinder,
bool inNextSplit) const bool inNextSplit) const
{ {
RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines); RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines);
QTC_ASSERT(engine, return Link();); QTC_ASSERT(engine, return;);
return engine->globalFollowSymbol(data, snapshot, documentFromSemanticInfo, engine->globalFollowSymbol(data, std::move(processLinkCallback), snapshot, documentFromSemanticInfo,
symbolFinder, inNextSplit); symbolFinder, inNextSplit);
} }
void CppModelManager::addRefactoringEngine(RefactoringEngineType type, void CppModelManager::addRefactoringEngine(RefactoringEngineType type,

View File

@@ -163,7 +163,8 @@ public:
const QString &replacement) final; const QString &replacement) final;
void findUsages(const CppTools::CursorInEditor &data, void findUsages(const CppTools::CursorInEditor &data,
UsagesCallback &&showUsagesCallback) const final; UsagesCallback &&showUsagesCallback) const final;
Link globalFollowSymbol(const CursorInEditor &data, void globalFollowSymbol(const CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder, SymbolFinder *symbolFinder,

View File

@@ -100,16 +100,17 @@ void CppRefactoringEngine::findUsages(const CursorInEditor &data,
} }
} }
CppRefactoringEngine::Link CppRefactoringEngine::globalFollowSymbol( void CppRefactoringEngine::globalFollowSymbol(
const CursorInEditor &data, const CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder, SymbolFinder *symbolFinder,
bool inNextSplit) const bool inNextSplit) const
{ {
FollowSymbolUnderCursor followSymbol; FollowSymbolUnderCursor followSymbol;
return followSymbol.findLink(data, true, snapshot, documentFromSemanticInfo, return followSymbol.findLink(data, std::move(processLinkCallback), true, snapshot,
symbolFinder, inNextSplit); documentFromSemanticInfo, symbolFinder, inNextSplit);
} }
} // namespace CppEditor } // namespace CppEditor

View File

@@ -38,7 +38,8 @@ public:
void globalRename(const CursorInEditor &data, UsagesCallback &&, void globalRename(const CursorInEditor &data, UsagesCallback &&,
const QString &replacement) override; const QString &replacement) override;
void findUsages(const CursorInEditor &data, UsagesCallback &&) const override; void findUsages(const CursorInEditor &data, UsagesCallback &&) const override;
Link globalFollowSymbol(const CursorInEditor &data, void globalFollowSymbol(const CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder, SymbolFinder *symbolFinder,

View File

@@ -42,7 +42,8 @@ public:
using Link = Utils::Link; using Link = Utils::Link;
virtual ~FollowSymbolInterface() {} virtual ~FollowSymbolInterface() {}
virtual Link findLink(const CursorInEditor &data, virtual void findLink(const CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget, bool resolveTarget,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,

View File

@@ -69,7 +69,8 @@ public:
const QString &replacement) = 0; const QString &replacement) = 0;
virtual void findUsages(const CppTools::CursorInEditor &data, virtual void findUsages(const CppTools::CursorInEditor &data,
UsagesCallback &&showUsagesCallback) const = 0; UsagesCallback &&showUsagesCallback) const = 0;
virtual Link globalFollowSymbol(const CursorInEditor &data, virtual void globalFollowSymbol(const CursorInEditor &data,
Utils::ProcessLinkCallback &&processLinkCallback,
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder, SymbolFinder *symbolFinder,

View File

@@ -57,7 +57,9 @@ namespace Internal {
class ProFileEditorWidget : public TextEditorWidget class ProFileEditorWidget : public TextEditorWidget
{ {
protected: protected:
virtual Link findLinkAt(const QTextCursor &, bool resolveTarget = true, virtual void findLinkAt(const QTextCursor &,
Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget = true,
bool inNextSplit = false) override; bool inNextSplit = false) override;
void contextMenuEvent(QContextMenuEvent *) override; void contextMenuEvent(QContextMenuEvent *) override;
}; };
@@ -72,9 +74,10 @@ static bool isValidFileNameChar(const QChar &c)
|| c == QLatin1Char('\\'); || c == QLatin1Char('\\');
} }
Utils::Link ProFileEditorWidget::findLinkAt(const QTextCursor &cursor, void ProFileEditorWidget::findLinkAt(const QTextCursor &cursor,
bool /*resolveTarget*/, Utils::ProcessLinkCallback &&processLinkCallback,
bool /*inNextSplit*/) bool /*resolveTarget*/,
bool /*inNextSplit*/)
{ {
Link link; Link link;
@@ -86,7 +89,7 @@ Utils::Link ProFileEditorWidget::findLinkAt(const QTextCursor &cursor,
// check if the current position is commented out // check if the current position is commented out
const int hashPos = block.indexOf(QLatin1Char('#')); const int hashPos = block.indexOf(QLatin1Char('#'));
if (hashPos >= 0 && hashPos < positionInBlock) if (hashPos >= 0 && hashPos < positionInBlock)
return link; return processLinkCallback(link);
// find the beginning of a filename // find the beginning of a filename
QString buffer; QString buffer;
@@ -159,7 +162,7 @@ Utils::Link ProFileEditorWidget::findLinkAt(const QTextCursor &cursor,
} }
if (buffer.isEmpty()) if (buffer.isEmpty())
return link; return processLinkCallback(link);
// remove trailing '\' since it can be line continuation char // remove trailing '\' since it can be line continuation char
if (buffer.at(buffer.size() - 1) == QLatin1Char('\\')) { if (buffer.at(buffer.size() - 1) == QLatin1Char('\\')) {
@@ -181,13 +184,13 @@ Utils::Link ProFileEditorWidget::findLinkAt(const QTextCursor &cursor,
if (QFileInfo::exists(subProject)) if (QFileInfo::exists(subProject))
fileName = subProject; fileName = subProject;
else else
return link; return processLinkCallback(link);
} }
link.targetFileName = QDir::cleanPath(fileName); link.targetFileName = QDir::cleanPath(fileName);
link.linkTextStart = cursor.position() - positionInBlock + beginPos + 1; link.linkTextStart = cursor.position() - positionInBlock + beginPos + 1;
link.linkTextEnd = cursor.position() - positionInBlock + endPos; link.linkTextEnd = cursor.position() - positionInBlock + endPos;
} }
return link; processLinkCallback(link);
} }
void ProFileEditorWidget::contextMenuEvent(QContextMenuEvent *e) void ProFileEditorWidget::contextMenuEvent(QContextMenuEvent *e)

View File

@@ -712,18 +712,19 @@ void QmlJSEditorWidget::inspectElementUnderCursor() const
widget->textDocument()->setPlainText(buf); widget->textDocument()->setPlainText(buf);
} }
Utils::Link QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor, void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
bool /*resolveTarget*/, Utils::ProcessLinkCallback &&processLinkCallback,
bool /*inNextSplit*/) bool /*resolveTarget*/,
bool /*inNextSplit*/)
{ {
const SemanticInfo semanticInfo = m_qmlJsEditorDocument->semanticInfo(); const SemanticInfo semanticInfo = m_qmlJsEditorDocument->semanticInfo();
if (! semanticInfo.isValid()) if (! semanticInfo.isValid())
return Utils::Link(); return processLinkCallback(Utils::Link());
const unsigned cursorPosition = cursor.position(); const unsigned cursorPosition = cursor.position();
AST::Node *node = semanticInfo.astNodeAt(cursorPosition); AST::Node *node = semanticInfo.astNodeAt(cursorPosition);
QTC_ASSERT(node, return Utils::Link()); QTC_ASSERT(node, return;);
if (AST::UiImport *importAst = cast<AST::UiImport *>(node)) { if (AST::UiImport *importAst = cast<AST::UiImport *>(node)) {
// if it's a file import, link to the file // if it's a file import, link to the file
@@ -732,10 +733,12 @@ Utils::Link QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
Utils::Link link(import.path()); Utils::Link link(import.path());
link.linkTextStart = importAst->firstSourceLocation().begin(); link.linkTextStart = importAst->firstSourceLocation().begin();
link.linkTextEnd = importAst->lastSourceLocation().end(); link.linkTextEnd = importAst->lastSourceLocation().end();
return link; processLinkCallback(Utils::Link());
return;
} }
} }
return Utils::Link(); processLinkCallback(Utils::Link());
return;
} }
// string literals that could refer to a file link to them // string literals that could refer to a file link to them
@@ -746,14 +749,16 @@ Utils::Link QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
link.linkTextEnd = literal->literalToken.end(); link.linkTextEnd = literal->literalToken.end();
if (semanticInfo.snapshot.document(text)) { if (semanticInfo.snapshot.document(text)) {
link.targetFileName = text; link.targetFileName = text;
return link; processLinkCallback(link);
return;
} }
const QString relative = QString::fromLatin1("%1/%2").arg( const QString relative = QString::fromLatin1("%1/%2").arg(
semanticInfo.document->path(), semanticInfo.document->path(),
text); text);
if (semanticInfo.snapshot.document(relative)) { if (semanticInfo.snapshot.document(relative)) {
link.targetFileName = relative; link.targetFileName = relative;
return link; processLinkCallback(link);
return;
} }
} }
@@ -765,7 +770,7 @@ Utils::Link QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
int line = 0, column = 0; int line = 0, column = 0;
if (! (value && value->getSourceLocation(&fileName, &line, &column))) if (! (value && value->getSourceLocation(&fileName, &line, &column)))
return Utils::Link(); return processLinkCallback(Utils::Link());
Utils::Link link; Utils::Link link;
link.targetFileName = fileName; link.targetFileName = fileName;
@@ -777,22 +782,25 @@ Utils::Link QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor,
if (! tail->next && cursorPosition <= tail->identifierToken.end()) { if (! tail->next && cursorPosition <= tail->identifierToken.end()) {
link.linkTextStart = tail->identifierToken.begin(); link.linkTextStart = tail->identifierToken.begin();
link.linkTextEnd = tail->identifierToken.end(); link.linkTextEnd = tail->identifierToken.end();
return link; processLinkCallback(link);
return;
} }
} }
} else if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(node)) { } else if (AST::IdentifierExpression *id = AST::cast<AST::IdentifierExpression *>(node)) {
link.linkTextStart = id->firstSourceLocation().begin(); link.linkTextStart = id->firstSourceLocation().begin();
link.linkTextEnd = id->lastSourceLocation().end(); link.linkTextEnd = id->lastSourceLocation().end();
return link; processLinkCallback(link);
return;
} else if (AST::FieldMemberExpression *mem = AST::cast<AST::FieldMemberExpression *>(node)) { } else if (AST::FieldMemberExpression *mem = AST::cast<AST::FieldMemberExpression *>(node)) {
link.linkTextStart = mem->lastSourceLocation().begin(); link.linkTextStart = mem->lastSourceLocation().begin();
link.linkTextEnd = mem->lastSourceLocation().end(); link.linkTextEnd = mem->lastSourceLocation().end();
return link; processLinkCallback(link);
return;
} }
return Utils::Link(); processLinkCallback(Utils::Link());
} }
void QmlJSEditorWidget::findUsages() void QmlJSEditorWidget::findUsages()

View File

@@ -103,9 +103,10 @@ protected:
void scrollContentsBy(int dx, int dy) override; void scrollContentsBy(int dx, int dy) override;
void applyFontSettings() override; void applyFontSettings() override;
void createToolBar(); void createToolBar();
Utils::Link findLinkAt(const QTextCursor &cursor, void findLinkAt(const QTextCursor &cursor,
bool resolveTarget = true, Utils::ProcessLinkCallback &&processLinkCallback,
bool inNextSplit = false) override; bool resolveTarget = true,
bool inNextSplit = false) override;
QString foldReplacementText(const QTextBlock &block) const override; QString foldReplacementText(const QTextBlock &block) const override;
void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker) override; void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker) override;

View File

@@ -1847,15 +1847,21 @@ void TextEditorWidget::redo()
void TextEditorWidget::openLinkUnderCursor() void TextEditorWidget::openLinkUnderCursor()
{ {
const bool openInNextSplit = alwaysOpenLinksInNextSplit(); const bool openInNextSplit = alwaysOpenLinksInNextSplit();
Utils::Link symbolLink = findLinkAt(textCursor(), true, openInNextSplit); findLinkAt(textCursor(),
openLink(symbolLink, openInNextSplit); [openInNextSplit, self = QPointer<TextEditorWidget>(this)](const Link &symbolLink) {
if (self)
self->openLink(symbolLink, openInNextSplit);
}, true, openInNextSplit);
} }
void TextEditorWidget::openLinkUnderCursorInNextSplit() void TextEditorWidget::openLinkUnderCursorInNextSplit()
{ {
const bool openInNextSplit = !alwaysOpenLinksInNextSplit(); const bool openInNextSplit = !alwaysOpenLinksInNextSplit();
Utils::Link symbolLink = findLinkAt(textCursor(), true, openInNextSplit); findLinkAt(textCursor(),
openLink(symbolLink, openInNextSplit); [openInNextSplit, self = QPointer<TextEditorWidget>(this)](const Link &symbolLink) {
if (self)
self->openLink(symbolLink, openInNextSplit);
}, true, openInNextSplit);
} }
void TextEditorWidget::abortAssist() void TextEditorWidget::abortAssist()
@@ -5581,10 +5587,12 @@ void TextEditorWidget::mouseReleaseEvent(QMouseEvent *e)
EditorManager::addCurrentPositionToNavigationHistory(); EditorManager::addCurrentPositionToNavigationHistory();
bool inNextSplit = ((e->modifiers() & Qt::AltModifier) && !alwaysOpenLinksInNextSplit()) bool inNextSplit = ((e->modifiers() & Qt::AltModifier) && !alwaysOpenLinksInNextSplit())
|| (alwaysOpenLinksInNextSplit() && !(e->modifiers() & Qt::AltModifier)); || (alwaysOpenLinksInNextSplit() && !(e->modifiers() & Qt::AltModifier));
if (openLink(findLinkAt(cursorForPosition(e->pos())), inNextSplit)) {
d->clearLink(); findLinkAt(textCursor(),
return; [inNextSplit, self = QPointer<TextEditorWidget>(this)](const Link &symbolLink) {
} if (self && self->openLink(symbolLink, inNextSplit))
self->d->clearLink();
}, true, inNextSplit);
} }
if (!HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(e)) if (!HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(e))
@@ -6136,9 +6144,8 @@ void TextEditorWidget::zoomReset()
showZoomIndicator(this, 100); showZoomIndicator(this, 100);
} }
Utils::Link TextEditorWidget::findLinkAt(const QTextCursor &, bool, bool) void TextEditorWidget::findLinkAt(const QTextCursor &, Utils::ProcessLinkCallback &&, bool, bool)
{ {
return Utils::Link();
} }
bool TextEditorWidget::openLink(const Utils::Link &link, bool inNextSplit) bool TextEditorWidget::openLink(const Utils::Link &link, bool inNextSplit)
@@ -6204,11 +6211,16 @@ void TextEditorWidgetPrivate::updateLink()
return; return;
m_lastLinkUpdate = m_pendingLinkUpdate; m_lastLinkUpdate = m_pendingLinkUpdate;
const Utils::Link link = q->findLinkAt(m_pendingLinkUpdate, false); q->findLinkAt(m_pendingLinkUpdate,
if (link.hasValidLinkText()) [parent = QPointer<TextEditorWidget>(q), this](const Link &link) {
showLink(link); if (!parent)
else return;
clearLink();
if (link.hasValidLinkText())
showLink(link);
else
clearLink();
}, false);
} }
void TextEditorWidgetPrivate::showLink(const Utils::Link &link) void TextEditorWidgetPrivate::showLink(const Utils::Link &link)

View File

@@ -548,8 +548,10 @@ protected:
\a resolveTarget is set to true when the target of the link is relevant \a resolveTarget is set to true when the target of the link is relevant
(it isn't until the link is used). (it isn't until the link is used).
*/ */
virtual Utils::Link findLinkAt(const QTextCursor &, bool resolveTarget = true, virtual void findLinkAt(const QTextCursor &,
bool inNextSplit = false); Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget = true,
bool inNextSplit = false);
/*! /*!
Returns whether the link was opened successfully. Returns whether the link was opened successfully.