forked from qt-creator/qt-creator
ClangCodeModel: Try harder to find out whether a function is virtual
... when following symbols with clangd. The textdocument/implementation request is expensive, so we'd like to make sure we only run it if we are sure that we're really dealing with a virtual function. We re-use the information gathered during highlighting for this purpose. Change-Id: Id92a9a92fe2ac7fd5acf903a9ade711223ee401b Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "clangcompletioncontextanalyzer.h"
|
||||
#include "clangdiagnosticmanager.h"
|
||||
#include "clangmodelmanagersupport.h"
|
||||
#include "clangpreprocessorassistproposalitem.h"
|
||||
#include "clangtextmark.h"
|
||||
#include "clangutils.h"
|
||||
@@ -654,6 +655,7 @@ public:
|
||||
bool openInSplit)
|
||||
: q(q), id(id), cursor(cursor), editorWidget(editorWidget), uri(uri),
|
||||
callback(std::move(callback)), virtualFuncAssistProvider(q->d),
|
||||
docRevision(editorWidget ? editorWidget->textDocument()->document()->revision() : -1),
|
||||
openInSplit(openInSplit) {}
|
||||
|
||||
~FollowSymbolData()
|
||||
@@ -678,6 +680,8 @@ public:
|
||||
openedFiles.clear();
|
||||
}
|
||||
|
||||
bool defLinkIsAmbiguous() const;
|
||||
|
||||
ClangdClient * const q;
|
||||
const quint64 id;
|
||||
const QTextCursor cursor;
|
||||
@@ -688,6 +692,7 @@ public:
|
||||
QList<MessageId> pendingSymbolInfoRequests;
|
||||
QList<MessageId> pendingGotoImplRequests;
|
||||
QList<MessageId> pendingGotoDefRequests;
|
||||
const int docRevision;
|
||||
const bool openInSplit;
|
||||
|
||||
Utils::Link defLink;
|
||||
@@ -1059,6 +1064,10 @@ public:
|
||||
// The highlighters are owned by their respective documents.
|
||||
std::unordered_map<TextDocument *, CppEditor::SemanticHighlighter *> highlighters;
|
||||
|
||||
// The ranges of symbols referring to virtual functions, with document version,
|
||||
// as extracted by the highlighting procedure.
|
||||
QHash<TextDocument *, QPair<QList<Range>, int>> virtualRanges;
|
||||
|
||||
VersionedDataCache<const TextDocument *, AstNode> astCache;
|
||||
VersionedDataCache<Utils::FilePath, AstNode> externalAstCache;
|
||||
TaskTimer highlightingTimer{"highlighting"};
|
||||
@@ -1366,6 +1375,7 @@ void ClangdClient::handleDocumentClosed(TextDocument *doc)
|
||||
{
|
||||
d->highlighters.erase(doc);
|
||||
d->astCache.remove(doc);
|
||||
d->virtualRanges.remove(doc);
|
||||
}
|
||||
|
||||
QVersionNumber ClangdClient::versionNumber() const
|
||||
@@ -1996,6 +2006,14 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
|
||||
d->getAndHandleAst(doc, astHandler, Private::AstCallbackMode::SyncIfPossible);
|
||||
}
|
||||
|
||||
void ClangdClient::setVirtualRanges(const Utils::FilePath &filePath, const QList<Range> &ranges,
|
||||
int revision)
|
||||
{
|
||||
TextDocument * const doc = documentForFilePath(filePath);
|
||||
if (doc && doc->document()->revision() == revision)
|
||||
d->virtualRanges.insert(doc, {ranges, revision});
|
||||
}
|
||||
|
||||
void ClangdClient::Private::handleGotoDefinitionResult()
|
||||
{
|
||||
QTC_ASSERT(followSymbolData->defLink.hasValidTarget(), return);
|
||||
@@ -2003,8 +2021,7 @@ void ClangdClient::Private::handleGotoDefinitionResult()
|
||||
qCDebug(clangdLog) << "handling go to definition result";
|
||||
|
||||
// No dis-ambiguation necessary. Call back with the link and finish.
|
||||
if (!followSymbolData->cursorNode->mightBeAmbiguousVirtualCall()
|
||||
&& !followSymbolData->cursorNode->isPureVirtualDeclaration()) {
|
||||
if (!followSymbolData->defLinkIsAmbiguous()) {
|
||||
followSymbolData->callback(followSymbolData->defLink);
|
||||
followSymbolData.reset();
|
||||
return;
|
||||
@@ -2491,6 +2508,20 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
|
||||
ExtraHighlightingResultsCollector(future, results, filePath, ast, &doc, docContents).collect();
|
||||
if (!future.isCanceled()) {
|
||||
qCDebug(clangdLog) << "reporting" << results.size() << "highlighting results";
|
||||
QList<Range> virtualRanges;
|
||||
for (const HighlightingResult &r : results) {
|
||||
if (r.textStyles.mainStyle != C_VIRTUAL_METHOD)
|
||||
continue;
|
||||
const Position startPos(r.line - 1, r.column - 1);
|
||||
virtualRanges << Range(startPos, startPos.withOffset(r.length, &doc));
|
||||
}
|
||||
QMetaObject::invokeMethod(ClangModelManagerSupport::instance(),
|
||||
[filePath, virtualRanges, docRevision] {
|
||||
if (ClangdClient * const client
|
||||
= ClangModelManagerSupport::instance()->clientForFile(filePath)) {
|
||||
client->setVirtualRanges(filePath, virtualRanges, docRevision);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
future.reportResults(QVector<HighlightingResult>(results.cbegin(),
|
||||
results.cend()));
|
||||
}
|
||||
@@ -3463,6 +3494,24 @@ void ExtraHighlightingResultsCollector::visitNode(const AstNode &node)
|
||||
}
|
||||
}
|
||||
|
||||
bool ClangdClient::FollowSymbolData::defLinkIsAmbiguous() const
|
||||
{
|
||||
// If we have up-to-date highlighting info, we can give a definite answer.
|
||||
if (editorWidget) {
|
||||
const auto virtualRanges = q->d->virtualRanges.constFind(editorWidget->textDocument());
|
||||
if (virtualRanges != q->d->virtualRanges.constEnd()
|
||||
&& virtualRanges->second == docRevision) {
|
||||
const auto matcher = [cursorRange = cursorNode->range()](const Range &r) {
|
||||
return cursorRange.overlaps(r);
|
||||
};
|
||||
return Utils::contains(virtualRanges->first, matcher);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we have to rely on AST-based heuristics.
|
||||
return cursorNode->mightBeAmbiguousVirtualCall() || cursorNode->isPureVirtualDeclaration();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
|
||||
namespace Core { class SearchResultItem; }
|
||||
namespace CppEditor { class CppEditorWidget; }
|
||||
namespace LanguageServerProtocol { class Range; }
|
||||
namespace ProjectExplorer { class Project; }
|
||||
namespace TextEditor { class BaseTextEditor; }
|
||||
|
||||
@@ -76,6 +77,9 @@ public:
|
||||
const LanguageServerProtocol::HoverRequest::Response &hoverResponse,
|
||||
const LanguageServerProtocol::DocumentUri &uri);
|
||||
|
||||
void setVirtualRanges(const Utils::FilePath &filePath,
|
||||
const QList<LanguageServerProtocol::Range> &ranges, int revision);
|
||||
|
||||
void enableTesting();
|
||||
bool testingEnabled() const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user