forked from qt-creator/qt-creator
ClangCodeModel: Allow more than one in-flight "follow symbol"
The original code was written with only the interactive case in mind, but nowadays we also start "follow symbol" operations internally as part of e.g. quickfixes. Change-Id: I95928297fab16f9b0469bfd66ad687447b902fd9 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -349,7 +349,7 @@ public:
|
|||||||
|
|
||||||
ClangdClient * const q;
|
ClangdClient * const q;
|
||||||
const CppEditor::ClangdSettings::Data settings;
|
const CppEditor::ClangdSettings::Data settings;
|
||||||
ClangdFollowSymbol *followSymbol = nullptr;
|
QList<ClangdFollowSymbol *> followSymbolOps;
|
||||||
ClangdSwitchDeclDef *switchDeclDef = nullptr;
|
ClangdSwitchDeclDef *switchDeclDef = nullptr;
|
||||||
ClangdFindLocalReferences *findLocalRefs = nullptr;
|
ClangdFindLocalReferences *findLocalRefs = nullptr;
|
||||||
std::optional<QVersionNumber> versionNumber;
|
std::optional<QVersionNumber> versionNumber;
|
||||||
@@ -501,8 +501,8 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir, c
|
|||||||
|
|
||||||
ClangdClient::~ClangdClient()
|
ClangdClient::~ClangdClient()
|
||||||
{
|
{
|
||||||
if (d->followSymbol)
|
for (ClangdFollowSymbol * const followSymbol : std::as_const(d->followSymbolOps))
|
||||||
d->followSymbol->clear();
|
followSymbol->clear();
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -990,7 +990,7 @@ MessageId ClangdClient::requestSymbolInfo(const Utils::FilePath &filePath, const
|
|||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
ClangdFollowSymbol *ClangdClient::currentFollowSymbolOperation()
|
ClangdFollowSymbol *ClangdClient::currentFollowSymbolOperation()
|
||||||
{
|
{
|
||||||
return d->followSymbol;
|
return d->followSymbolOps.isEmpty() ? nullptr : d->followSymbolOps.first();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1005,8 +1005,20 @@ void ClangdClient::followSymbol(TextDocument *document,
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(documentOpen(document), openDocument(document));
|
QTC_ASSERT(documentOpen(document), openDocument(document));
|
||||||
|
|
||||||
if (d->followSymbol)
|
const ClangdFollowSymbol::Origin origin
|
||||||
d->followSymbol->cancel();
|
= CppEditor::CppCodeModelSettings::isInteractiveFollowSymbol()
|
||||||
|
? ClangdFollowSymbol::Origin::User
|
||||||
|
: ClangdFollowSymbol::Origin::Code;
|
||||||
|
if (origin == ClangdFollowSymbol::Origin::User) {
|
||||||
|
for (auto it = d->followSymbolOps.begin(); it != d->followSymbolOps.end(); ) {
|
||||||
|
if ((*it)->isInteractive()) {
|
||||||
|
(*it)->cancel();
|
||||||
|
it = d->followSymbolOps.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const QTextCursor adjustedCursor = d->adjustedCursor(cursor, document);
|
const QTextCursor adjustedCursor = d->adjustedCursor(cursor, document);
|
||||||
if (followTo == FollowTo::SymbolDef && !resolveTarget) {
|
if (followTo == FollowTo::SymbolDef && !resolveTarget) {
|
||||||
@@ -1020,14 +1032,13 @@ void ClangdClient::followSymbol(TextDocument *document,
|
|||||||
|
|
||||||
qCDebug(clangdLog) << "follow symbol requested" << document->filePath()
|
qCDebug(clangdLog) << "follow symbol requested" << document->filePath()
|
||||||
<< adjustedCursor.blockNumber() << adjustedCursor.positionInBlock();
|
<< adjustedCursor.blockNumber() << adjustedCursor.positionInBlock();
|
||||||
auto clangdFollowSymbol = new ClangdFollowSymbol(this, adjustedCursor, editorWidget, document,
|
auto clangdFollowSymbol = new ClangdFollowSymbol(this, origin, adjustedCursor, editorWidget,
|
||||||
callback, followTo, openInSplit);
|
document, callback, followTo, openInSplit);
|
||||||
connect(clangdFollowSymbol, &ClangdFollowSymbol::done, this, [this, clangdFollowSymbol] {
|
connect(clangdFollowSymbol, &ClangdFollowSymbol::done, this, [this, clangdFollowSymbol] {
|
||||||
clangdFollowSymbol->deleteLater();
|
clangdFollowSymbol->deleteLater();
|
||||||
if (clangdFollowSymbol == d->followSymbol)
|
d->followSymbolOps.removeOne(clangdFollowSymbol);
|
||||||
d->followSymbol = nullptr;
|
|
||||||
});
|
});
|
||||||
d->followSymbol = clangdFollowSymbol;
|
d->followSymbolOps << clangdFollowSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangdClient::switchDeclDef(TextDocument *document, const QTextCursor &cursor,
|
void ClangdClient::switchDeclDef(TextDocument *document, const QTextCursor &cursor,
|
||||||
|
@@ -73,10 +73,10 @@ private:
|
|||||||
class ClangdFollowSymbol::Private
|
class ClangdFollowSymbol::Private
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Private(ClangdFollowSymbol *q, ClangdClient *client, const QTextCursor &cursor,
|
Private(ClangdFollowSymbol *q, ClangdClient *client, Origin origin, const QTextCursor &cursor,
|
||||||
CppEditorWidget *editorWidget, const FilePath &filePath, const LinkHandler &callback,
|
CppEditorWidget *editorWidget, const FilePath &filePath, const LinkHandler &callback,
|
||||||
bool openInSplit)
|
bool openInSplit)
|
||||||
: q(q), client(client), cursor(cursor), editorWidget(editorWidget),
|
: q(q), client(client), origin(origin), cursor(cursor), editorWidget(editorWidget),
|
||||||
uri(client->hostPathToServerUri(filePath)), callback(callback),
|
uri(client->hostPathToServerUri(filePath)), callback(callback),
|
||||||
virtualFuncAssistProvider(q),
|
virtualFuncAssistProvider(q),
|
||||||
docRevision(editorWidget ? editorWidget->textDocument()->document()->revision() : -1),
|
docRevision(editorWidget ? editorWidget->textDocument()->document()->revision() : -1),
|
||||||
@@ -94,6 +94,7 @@ public:
|
|||||||
|
|
||||||
ClangdFollowSymbol * const q;
|
ClangdFollowSymbol * const q;
|
||||||
ClangdClient * const client;
|
ClangdClient * const client;
|
||||||
|
const Origin origin;
|
||||||
const QTextCursor cursor;
|
const QTextCursor cursor;
|
||||||
const QPointer<CppEditor::CppEditorWidget> editorWidget;
|
const QPointer<CppEditor::CppEditorWidget> editorWidget;
|
||||||
const DocumentUri uri;
|
const DocumentUri uri;
|
||||||
@@ -117,11 +118,11 @@ public:
|
|||||||
bool done = false;
|
bool done = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClangdFollowSymbol::ClangdFollowSymbol(ClangdClient *client, const QTextCursor &cursor,
|
ClangdFollowSymbol::ClangdFollowSymbol(ClangdClient *client, Origin origin,
|
||||||
CppEditorWidget *editorWidget, TextDocument *document, const LinkHandler &callback,
|
const QTextCursor &cursor, CppEditorWidget *editorWidget, TextDocument *document,
|
||||||
FollowTo followTo, bool openInSplit)
|
const LinkHandler &callback, FollowTo followTo, bool openInSplit)
|
||||||
: QObject(client),
|
: QObject(client),
|
||||||
d(new Private(this, client, cursor, editorWidget, document->filePath(), callback,
|
d(new Private(this, client, origin, cursor, editorWidget, document->filePath(), callback,
|
||||||
openInSplit))
|
openInSplit))
|
||||||
{
|
{
|
||||||
// Abort if the user does something else with the document in the meantime.
|
// Abort if the user does something else with the document in the meantime.
|
||||||
@@ -193,6 +194,11 @@ void ClangdFollowSymbol::clear()
|
|||||||
d->pendingGotoDefRequests.clear();
|
d->pendingGotoDefRequests.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClangdFollowSymbol::isInteractive() const
|
||||||
|
{
|
||||||
|
return d->origin == Origin::User;
|
||||||
|
}
|
||||||
|
|
||||||
void ClangdFollowSymbol::emitDone(const Link &link)
|
void ClangdFollowSymbol::emitDone(const Link &link)
|
||||||
{
|
{
|
||||||
if (d->done)
|
if (d->done)
|
||||||
|
@@ -23,7 +23,9 @@ class ClangdFollowSymbol : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ClangdFollowSymbol(ClangdClient *client, const QTextCursor &cursor,
|
enum class Origin { User, Code };
|
||||||
|
|
||||||
|
ClangdFollowSymbol(ClangdClient *client, Origin origin, const QTextCursor &cursor,
|
||||||
CppEditor::CppEditorWidget *editorWidget,
|
CppEditor::CppEditorWidget *editorWidget,
|
||||||
TextEditor::TextDocument *document, const Utils::LinkHandler &callback,
|
TextEditor::TextDocument *document, const Utils::LinkHandler &callback,
|
||||||
FollowTo followTo, bool openInSplit);
|
FollowTo followTo, bool openInSplit);
|
||||||
@@ -31,6 +33,8 @@ public:
|
|||||||
void cancel();
|
void cancel();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
bool isInteractive() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void done();
|
void done();
|
||||||
|
|
||||||
|
@@ -83,6 +83,7 @@ bool operator==(const CppEditor::CppCodeModelSettings &s1,
|
|||||||
&& s1.useBuiltinPreprocessor == s2.useBuiltinPreprocessor
|
&& s1.useBuiltinPreprocessor == s2.useBuiltinPreprocessor
|
||||||
&& s1.indexerFileSizeLimitInMb == s2.indexerFileSizeLimitInMb
|
&& s1.indexerFileSizeLimitInMb == s2.indexerFileSizeLimitInMb
|
||||||
&& s1.m_categorizeFindReferences == s2.m_categorizeFindReferences
|
&& s1.m_categorizeFindReferences == s2.m_categorizeFindReferences
|
||||||
|
&& s1.interactiveFollowSymbol == s2.interactiveFollowSymbol
|
||||||
&& s1.ignoreFiles == s2.ignoreFiles && s1.ignorePattern == s2.ignorePattern;
|
&& s1.ignoreFiles == s2.ignoreFiles && s1.ignorePattern == s2.ignorePattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +205,16 @@ void CppCodeModelSettings::setCategorizeFindReferences(bool categorize)
|
|||||||
globalInstance().m_categorizeFindReferences = categorize;
|
globalInstance().m_categorizeFindReferences = categorize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CppCodeModelSettings::isInteractiveFollowSymbol()
|
||||||
|
{
|
||||||
|
return globalInstance().interactiveFollowSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CppCodeModelSettings::setInteractiveFollowSymbol(bool interactive)
|
||||||
|
{
|
||||||
|
globalInstance().interactiveFollowSymbol = interactive;
|
||||||
|
}
|
||||||
|
|
||||||
CppCodeModelProjectSettings::CppCodeModelProjectSettings(ProjectExplorer::Project *project)
|
CppCodeModelProjectSettings::CppCodeModelProjectSettings(ProjectExplorer::Project *project)
|
||||||
: m_project(project)
|
: m_project(project)
|
||||||
{
|
{
|
||||||
|
@@ -55,6 +55,9 @@ public:
|
|||||||
static bool categorizeFindReferences();
|
static bool categorizeFindReferences();
|
||||||
static void setCategorizeFindReferences(bool categorize);
|
static void setCategorizeFindReferences(bool categorize);
|
||||||
|
|
||||||
|
static bool isInteractiveFollowSymbol();
|
||||||
|
static void setInteractiveFollowSymbol(bool interactive);
|
||||||
|
|
||||||
QString ignorePattern;
|
QString ignorePattern;
|
||||||
PCHUsage pchUsage = PchUse_BuildSystem;
|
PCHUsage pchUsage = PchUse_BuildSystem;
|
||||||
int indexerFileSizeLimitInMb = 5;
|
int indexerFileSizeLimitInMb = 5;
|
||||||
@@ -63,7 +66,10 @@ public:
|
|||||||
bool useBuiltinPreprocessor = true;
|
bool useBuiltinPreprocessor = true;
|
||||||
bool ignoreFiles = false;
|
bool ignoreFiles = false;
|
||||||
bool enableIndexing = true;
|
bool enableIndexing = true;
|
||||||
bool m_categorizeFindReferences = false; // Ephemeral!
|
|
||||||
|
// Ephemeral!
|
||||||
|
bool m_categorizeFindReferences = false;
|
||||||
|
bool interactiveFollowSymbol = true;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CppCodeModelSettings(Utils::QtcSettings *s) { fromSettings(s); }
|
CppCodeModelSettings(Utils::QtcSettings *s) { fromSettings(s); }
|
||||||
@@ -76,6 +82,14 @@ private:
|
|||||||
namespace Internal {
|
namespace Internal {
|
||||||
void setupCppCodeModelSettingsPage();
|
void setupCppCodeModelSettingsPage();
|
||||||
void setupCppCodeModelProjectSettingsPanel();
|
void setupCppCodeModelProjectSettingsPanel();
|
||||||
|
|
||||||
|
class NonInteractiveFollowSymbolMarker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NonInteractiveFollowSymbolMarker() { CppCodeModelSettings::setInteractiveFollowSymbol(false); }
|
||||||
|
~NonInteractiveFollowSymbolMarker() { CppCodeModelSettings::setInteractiveFollowSymbol(true); }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
} // namespace CppEditor
|
} // namespace CppEditor
|
||||||
|
@@ -623,6 +623,7 @@ void CppEditorWidget::renameUsages(const QString &replacement, QTextCursor curso
|
|||||||
const CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this, textDocument()};
|
const CursorInEditor cursorInEditor{cursor, textDocument()->filePath(), this, textDocument()};
|
||||||
CppModelManager::globalRename(cursorInEditor, replacement);
|
CppModelManager::globalRename(cursorInEditor, replacement);
|
||||||
};
|
};
|
||||||
|
NonInteractiveFollowSymbolMarker niMarker;
|
||||||
CppModelManager::followSymbol(CursorInEditor{cursor,
|
CppModelManager::followSymbol(CursorInEditor{cursor,
|
||||||
textDocument()->filePath(),
|
textDocument()->filePath(),
|
||||||
this,
|
this,
|
||||||
|
@@ -370,6 +370,7 @@ private:
|
|||||||
if (!link.hasValidTarget())
|
if (!link.hasValidTarget())
|
||||||
collectOperations(interface, result);
|
collectOperations(interface, result);
|
||||||
};
|
};
|
||||||
|
NonInteractiveFollowSymbolMarker niMarker;
|
||||||
CppModelManager::followSymbol(cursorInEditor, followSymbolFallback, false, false,
|
CppModelManager::followSymbol(cursorInEditor, followSymbolFallback, false, false,
|
||||||
FollowSymbolMode::Exact,
|
FollowSymbolMode::Exact,
|
||||||
CppModelManager::Backend::Builtin);
|
CppModelManager::Backend::Builtin);
|
||||||
|
@@ -294,6 +294,7 @@ private:
|
|||||||
|
|
||||||
// Force queued execution, as the built-in editor can run the callback synchronously.
|
// Force queued execution, as the built-in editor can run the callback synchronously.
|
||||||
const auto followSymbol = [cursorInEditor, callback] {
|
const auto followSymbol = [cursorInEditor, callback] {
|
||||||
|
NonInteractiveFollowSymbolMarker niMarker;
|
||||||
CppModelManager::followSymbol(
|
CppModelManager::followSymbol(
|
||||||
cursorInEditor, callback, true, false, FollowSymbolMode::Exact);
|
cursorInEditor, callback, true, false, FollowSymbolMode::Exact);
|
||||||
};
|
};
|
||||||
|
@@ -246,6 +246,8 @@ private:
|
|||||||
(const Link &link) {
|
(const Link &link) {
|
||||||
moveComments(link, symbolLoc, comments);
|
moveComments(link, symbolLoc, comments);
|
||||||
};
|
};
|
||||||
|
NonInteractiveFollowSymbolMarker niMarker;
|
||||||
|
CppCodeModelSettings::setInteractiveFollowSymbol(false);
|
||||||
CppModelManager::followSymbol(cursorInEditor, callback, true, false,
|
CppModelManager::followSymbol(cursorInEditor, callback, true, false,
|
||||||
FollowSymbolMode::Exact);
|
FollowSymbolMode::Exact);
|
||||||
}
|
}
|
||||||
|
@@ -120,6 +120,7 @@ private:
|
|||||||
|
|
||||||
// Force queued execution, as the built-in editor can run the callback synchronously.
|
// Force queued execution, as the built-in editor can run the callback synchronously.
|
||||||
const auto followSymbol = [cursorInEditor, callback] {
|
const auto followSymbol = [cursorInEditor, callback] {
|
||||||
|
NonInteractiveFollowSymbolMarker niMarker;
|
||||||
CppModelManager::followSymbol(
|
CppModelManager::followSymbol(
|
||||||
cursorInEditor, callback, true, false, FollowSymbolMode::Exact);
|
cursorInEditor, callback, true, false, FollowSymbolMode::Exact);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user