forked from qt-creator/qt-creator
ClangCodeModel: Implement declaration/definition switch via clangd
Change-Id: I522a415d76fbc5332e5cc1fdfd2d7ab19cb9ed64 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -230,7 +230,8 @@ public:
|
||||
void print(int indent = 0) const
|
||||
{
|
||||
(qDebug().noquote() << QByteArray(indent, ' ')).quote() << role() << kind()
|
||||
<< detail().value_or(QString()) << arcana().value_or(QString());
|
||||
<< detail().value_or(QString()) << arcana().value_or(QString())
|
||||
<< range();
|
||||
for (const AstNode &c : children().value_or(QList<AstNode>()))
|
||||
c.print(indent + 2);
|
||||
}
|
||||
@@ -512,6 +513,58 @@ public:
|
||||
VirtualFunctionAssistProcessor *virtualFuncAssistProcessor = nullptr;
|
||||
};
|
||||
|
||||
class SwitchDeclDefData {
|
||||
public:
|
||||
SwitchDeclDefData(quint64 id, TextEditor::TextDocument *doc, const QTextCursor &cursor,
|
||||
CppTools::CppEditorWidgetInterface *editorWidget,
|
||||
Utils::ProcessLinkCallback &&callback)
|
||||
: id(id), document(doc), uri(DocumentUri::fromFilePath(doc->filePath())),
|
||||
cursor(cursor), editorWidget(editorWidget), callback(std::move(callback)) {}
|
||||
|
||||
Utils::optional<AstNode> getFunctionNode() const
|
||||
{
|
||||
QTC_ASSERT(ast, return {});
|
||||
|
||||
const QList<AstNode> path = getAstPath(*ast, Range(cursor));
|
||||
for (auto it = path.rbegin(); it != path.rend(); ++it) {
|
||||
if (it->role() == "declaration"
|
||||
&& (it->kind() == "CXXMethod" || it->kind() == "CXXConversion"
|
||||
|| it->kind() == "CXXConstructor" || it->kind() == "CXXDestructor")) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QTextCursor cursorForFunctionName(const AstNode &functionNode) const
|
||||
{
|
||||
QTC_ASSERT(docSymbols, return {});
|
||||
|
||||
const auto symbolList = Utils::get_if<QList<DocumentSymbol>>(&*docSymbols);
|
||||
if (!symbolList)
|
||||
return {};
|
||||
const Range &astRange = functionNode.range();
|
||||
QList symbolsToCheck = *symbolList;
|
||||
while (!symbolsToCheck.isEmpty()) {
|
||||
const DocumentSymbol symbol = symbolsToCheck.takeFirst();
|
||||
if (symbol.range() == astRange)
|
||||
return symbol.selectionRange().start().toTextCursor(document->document());
|
||||
if (symbol.range().contains(astRange))
|
||||
symbolsToCheck << symbol.children().value_or(QList<DocumentSymbol>());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
const quint64 id;
|
||||
const QPointer<TextEditor::TextDocument> document;
|
||||
const DocumentUri uri;
|
||||
const QTextCursor cursor;
|
||||
CppTools::CppEditorWidgetInterface * const editorWidget;
|
||||
Utils::ProcessLinkCallback callback;
|
||||
Utils::optional<DocumentSymbolsResult> docSymbols;
|
||||
Utils::optional<AstNode> ast;
|
||||
};
|
||||
|
||||
|
||||
class ClangdClient::Private
|
||||
{
|
||||
@@ -535,12 +588,16 @@ public:
|
||||
void handleDocumentInfoResults();
|
||||
void closeTempDocuments();
|
||||
|
||||
void handleDeclDefSwitchReplies();
|
||||
|
||||
ClangdClient * const q;
|
||||
QHash<quint64, ReferencesData> runningFindUsages;
|
||||
Utils::optional<FollowSymbolData> followSymbolData;
|
||||
Utils::optional<SwitchDeclDefData> switchDeclDefData;
|
||||
Utils::optional<QVersionNumber> versionNumber;
|
||||
quint64 nextFindUsagesKey = 0;
|
||||
quint64 nextFollowSymbolId = 0;
|
||||
quint64 nextSwitchDeclDefId = 0;
|
||||
bool isFullyIndexed = false;
|
||||
bool isTesting = false;
|
||||
};
|
||||
@@ -555,7 +612,6 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
|
||||
setSupportedLanguage(langFilter);
|
||||
LanguageServerProtocol::ClientCapabilities caps = Client::defaultClientCapabilities();
|
||||
caps.clearExperimental();
|
||||
caps.clearTextDocument();
|
||||
setClientCapabilities(caps);
|
||||
setLocatorsEnabled(false);
|
||||
setProgressTitleForToken(indexingToken(), tr("Parsing C/C++ Files (clangd)"));
|
||||
@@ -581,6 +637,15 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
|
||||
QTC_CHECK(d->runningFindUsages.isEmpty());
|
||||
});
|
||||
|
||||
connect(documentSymbolCache(), &DocumentSymbolCache::gotSymbols, this,
|
||||
[this](const DocumentUri &uri, const DocumentSymbolsResult &symbols) {
|
||||
if (!d->switchDeclDefData || d->switchDeclDefData->uri != uri)
|
||||
return;
|
||||
d->switchDeclDefData->docSymbols = symbols;
|
||||
if (d->switchDeclDefData->ast)
|
||||
d->handleDeclDefSwitchReplies();
|
||||
});
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
@@ -943,6 +1008,42 @@ void ClangdClient::followSymbol(
|
||||
sendContent(astRequest);
|
||||
}
|
||||
|
||||
void ClangdClient::switchDeclDef(TextEditor::TextDocument *document, const QTextCursor &cursor,
|
||||
CppTools::CppEditorWidgetInterface *editorWidget,
|
||||
Utils::ProcessLinkCallback &&callback)
|
||||
{
|
||||
QTC_ASSERT(documentOpen(document), openDocument(document));
|
||||
|
||||
qCDebug(clangdLog) << "switch decl/dev requested" << document->filePath()
|
||||
<< cursor.blockNumber() << cursor.positionInBlock();
|
||||
d->switchDeclDefData.emplace(++d->nextSwitchDeclDefId, document, cursor, editorWidget,
|
||||
std::move(callback));
|
||||
|
||||
// Retrieve AST and document symbols.
|
||||
AstParams astParams;
|
||||
astParams.setTextDocument(TextDocumentIdentifier(d->switchDeclDefData->uri));
|
||||
AstRequest astRequest(astParams);
|
||||
astRequest.setResponseCallback([this, id = d->switchDeclDefData->id]
|
||||
(const AstRequest::Response &response) {
|
||||
qCDebug(clangdLog) << "received ast for decl/def switch";
|
||||
if (!d->switchDeclDefData || d->switchDeclDefData->id != id
|
||||
|| !d->switchDeclDefData->document)
|
||||
return;
|
||||
const auto result = response.result();
|
||||
if (!result) {
|
||||
d->switchDeclDefData.reset();
|
||||
return;
|
||||
}
|
||||
d->switchDeclDefData->ast = *result;
|
||||
if (d->switchDeclDefData->docSymbols)
|
||||
d->handleDeclDefSwitchReplies();
|
||||
|
||||
});
|
||||
sendContent(astRequest);
|
||||
documentSymbolCache()->requestSymbols(d->switchDeclDefData->uri);
|
||||
|
||||
}
|
||||
|
||||
void ClangdClient::Private::handleGotoDefinitionResult()
|
||||
{
|
||||
QTC_ASSERT(followSymbolData->defLink.hasValidTarget(), return);
|
||||
@@ -1144,6 +1245,35 @@ void ClangdClient::Private::handleDocumentInfoResults()
|
||||
followSymbolData->virtualFuncAssistProcessor->finalize();
|
||||
}
|
||||
|
||||
void ClangdClient::Private::handleDeclDefSwitchReplies()
|
||||
{
|
||||
if (!switchDeclDefData->document) {
|
||||
switchDeclDefData.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the function declaration or definition associated with the cursor.
|
||||
// For instance, the cursor could be somwehere inside a function body or
|
||||
// on a function return type, or ...
|
||||
if (clangdLog().isDebugEnabled())
|
||||
switchDeclDefData->ast->print(0);
|
||||
const Utils::optional<AstNode> functionNode = switchDeclDefData->getFunctionNode();
|
||||
if (!functionNode) {
|
||||
switchDeclDefData.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// Unfortunately, the AST does not contain the location of the actual function name symbol,
|
||||
// so we have to look for it in the document symbols.
|
||||
const QTextCursor funcNameCursor = switchDeclDefData->cursorForFunctionName(*functionNode);
|
||||
if (!funcNameCursor.isNull()) {
|
||||
q->followSymbol(switchDeclDefData->document.data(), funcNameCursor,
|
||||
switchDeclDefData->editorWidget, std::move(switchDeclDefData->callback),
|
||||
true, false);
|
||||
}
|
||||
switchDeclDefData.reset();
|
||||
}
|
||||
|
||||
void ClangdClient::VirtualFunctionAssistProcessor::cancel()
|
||||
{
|
||||
if (!m_data)
|
||||
|
@@ -61,6 +61,11 @@ public:
|
||||
bool resolveTarget,
|
||||
bool openInSplit);
|
||||
|
||||
void switchDeclDef(TextEditor::TextDocument *document,
|
||||
const QTextCursor &cursor,
|
||||
CppTools::CppEditorWidgetInterface *editorWidget,
|
||||
Utils::ProcessLinkCallback &&callback);
|
||||
|
||||
void enableTesting();
|
||||
|
||||
signals:
|
||||
|
@@ -251,5 +251,23 @@ void ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
|
||||
m_watcher->setFuture(infoFuture);
|
||||
}
|
||||
|
||||
void ClangFollowSymbol::switchDeclDef(const CppTools::CursorInEditor &data,
|
||||
Utils::ProcessLinkCallback &&processLinkCallback,
|
||||
const CPlusPlus::Snapshot &snapshot,
|
||||
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||
CppTools::SymbolFinder *symbolFinder)
|
||||
{
|
||||
ClangdClient * const client
|
||||
= ClangModelManagerSupport::instance()->clientForFile(data.filePath());
|
||||
if (client && client->isFullyIndexed() && client->versionNumber() >= QVersionNumber(13)) {
|
||||
client->switchDeclDef(data.textDocument(), data.cursor(), data.editorWidget(),
|
||||
std::move(processLinkCallback));
|
||||
return;
|
||||
}
|
||||
CppTools::CppModelManager::builtinFollowSymbol().switchDeclDef(
|
||||
data, std::move(processLinkCallback), snapshot, documentFromSemanticInfo,
|
||||
symbolFinder);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
|
@@ -43,9 +43,17 @@ public:
|
||||
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||
CppTools::SymbolFinder *symbolFinder,
|
||||
bool inNextSplit) override;
|
||||
|
||||
void switchDeclDef(const CppTools::CursorInEditor &data,
|
||||
Utils::ProcessLinkCallback &&processLinkCallback,
|
||||
const CPlusPlus::Snapshot &snapshot,
|
||||
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||
CppTools::SymbolFinder *symbolFinder) override;
|
||||
|
||||
private:
|
||||
using FutureSymbolWatcher = QFutureWatcher<CppTools::SymbolInfo>;
|
||||
std::unique_ptr<FutureSymbolWatcher> m_watcher;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -711,78 +711,15 @@ void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit)
|
||||
if (!d->m_modelManager)
|
||||
return;
|
||||
|
||||
if (!d->m_lastSemanticInfo.doc)
|
||||
return;
|
||||
|
||||
// Find function declaration or definition under cursor
|
||||
Function *functionDefinitionSymbol = nullptr;
|
||||
Symbol *functionDeclarationSymbol = nullptr;
|
||||
Symbol *declarationSymbol = nullptr;
|
||||
|
||||
ASTPath astPathFinder(d->m_lastSemanticInfo.doc);
|
||||
const QList<AST *> astPath = astPathFinder(textCursor());
|
||||
|
||||
for (AST *ast : astPath) {
|
||||
if (FunctionDefinitionAST *functionDefinitionAST = ast->asFunctionDefinition()) {
|
||||
if ((functionDefinitionSymbol = functionDefinitionAST->symbol))
|
||||
break; // Function definition found!
|
||||
} else if (SimpleDeclarationAST *simpleDeclaration = ast->asSimpleDeclaration()) {
|
||||
if (List<Symbol *> *symbols = simpleDeclaration->symbols) {
|
||||
if (Symbol *symbol = symbols->value) {
|
||||
if (symbol->isDeclaration()) {
|
||||
declarationSymbol = symbol;
|
||||
if (symbol->type()->isFunctionType()) {
|
||||
functionDeclarationSymbol = symbol;
|
||||
break; // Function declaration found!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Link to function definition/declaration
|
||||
Utils::Link symbolLink;
|
||||
if (functionDeclarationSymbol) {
|
||||
Symbol *symbol = d->m_modelManager->symbolFinder()
|
||||
->findMatchingDefinition(functionDeclarationSymbol, d->m_modelManager->snapshot());
|
||||
if (symbol)
|
||||
symbolLink = symbol->toLink();
|
||||
} else if (declarationSymbol) {
|
||||
Symbol *symbol = d->m_modelManager->symbolFinder()
|
||||
->findMatchingVarDefinition(declarationSymbol, d->m_modelManager->snapshot());
|
||||
if (symbol)
|
||||
symbolLink = symbol->toLink();
|
||||
} else if (functionDefinitionSymbol) {
|
||||
const Snapshot snapshot = d->m_modelManager->snapshot();
|
||||
LookupContext context(d->m_lastSemanticInfo.doc, snapshot);
|
||||
ClassOrNamespace *binding = context.lookupType(functionDefinitionSymbol);
|
||||
const QList<LookupItem> declarations
|
||||
= context.lookup(functionDefinitionSymbol->name(),
|
||||
functionDefinitionSymbol->enclosingScope());
|
||||
|
||||
QList<Symbol *> best;
|
||||
foreach (const LookupItem &r, declarations) {
|
||||
if (Symbol *decl = r.declaration()) {
|
||||
if (Function *funTy = decl->type()->asFunctionType()) {
|
||||
if (funTy->match(functionDefinitionSymbol)) {
|
||||
if (decl != functionDefinitionSymbol && binding == r.binding())
|
||||
best.prepend(decl);
|
||||
else
|
||||
best.append(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best.isEmpty())
|
||||
return;
|
||||
symbolLink = best.first()->toLink();
|
||||
}
|
||||
|
||||
// Open Editor at link position
|
||||
if (symbolLink.hasValidTarget())
|
||||
openLink(symbolLink, inNextSplit != alwaysOpenLinksInNextSplit());
|
||||
const CursorInEditor cursor(textCursor(), textDocument()->filePath(), this, textDocument());
|
||||
auto callback = [self = QPointer(this),
|
||||
split = inNextSplit != alwaysOpenLinksInNextSplit()](const Link &link) {
|
||||
if (self && link.hasValidTarget())
|
||||
self->openLink(link, split);
|
||||
};
|
||||
followSymbolInterface().switchDeclDef(cursor, std::move(callback),
|
||||
d->m_modelManager->snapshot(), d->m_lastSemanticInfo.doc,
|
||||
d->m_modelManager->symbolFinder());
|
||||
}
|
||||
|
||||
void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
|
||||
|
@@ -297,14 +297,12 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
QSKIP("fuzzy matching is not supposed to work with clangd"); // TODO: Implement fallback as we do with libclang
|
||||
if (tag == "baseClassFunctionIntroducedByUsingDeclaration")
|
||||
QSKIP("clangd points to the using declaration");
|
||||
if (tag == "classDestructor")
|
||||
if (tag == "classDestructor" || tag == "fromDestructorDefinitionSymbol"
|
||||
|| tag == "fromDestructorBody") {
|
||||
QSKIP("clangd wants the cursor before the ~ character");
|
||||
}
|
||||
if (curTestName == "test_FollowSymbolUnderCursor_classOperator_inOp")
|
||||
QSKIP("clangd goes to operator name first");
|
||||
if (tag == "fromFunctionBody" || tag == "fromReturnType"
|
||||
|| tag == "conversionOperatorDecl2Def") {
|
||||
QSKIP("TODO: explicit decl/def switch not yet supported with clangd");
|
||||
}
|
||||
}
|
||||
|
||||
// Write files to disk
|
||||
@@ -415,7 +413,9 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
||||
break;
|
||||
}
|
||||
case SwitchBetweenMethodDeclarationDefinitionAction:
|
||||
if (CppTools::codeModelSettings()->useClangd())
|
||||
// Some test cases were erroneously added as decl/def, but they are really
|
||||
// follow symbol functionality (in commit a0764603d0).
|
||||
if (useClangd && tag.endsWith("Var"))
|
||||
initialTestFile->m_editorWidget->openLinkUnderCursor();
|
||||
else
|
||||
CppEditorPlugin::instance()->switchDeclarationDefinition();
|
||||
@@ -623,6 +623,126 @@ void CppEditorPlugin::test_SwitchMethodDeclarationDefinition_data()
|
||||
"}\n" // Line 10
|
||||
);
|
||||
|
||||
QTest::newRow("fromConstructorDeclarationSymbol") << _(
|
||||
"class C\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" C();\n"
|
||||
" int @function();\n" // Line 5
|
||||
"};\n"
|
||||
) << _(
|
||||
"#include \"file.h\"\n"
|
||||
"\n"
|
||||
"C::C()\n"
|
||||
"{\n"
|
||||
"}\n" // Line 5
|
||||
"\n"
|
||||
"int C::$function()\n"
|
||||
"{\n"
|
||||
" return 1 + 1;\n"
|
||||
"}\n" // Line 10
|
||||
);
|
||||
|
||||
QTest::newRow("fromConstructorDefinitionSymbol") << _(
|
||||
"class C\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" $C();\n"
|
||||
" int function();\n"
|
||||
"};\n"
|
||||
) << _(
|
||||
"#include \"file.h\"\n"
|
||||
"\n"
|
||||
"C::@C()\n"
|
||||
"{\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"int C::function()\n"
|
||||
"{\n"
|
||||
" return 1 + 1;\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
QTest::newRow("fromConstructorBody") << _(
|
||||
"class C\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" $C();\n"
|
||||
" int function();\n"
|
||||
"};\n"
|
||||
) << _(
|
||||
"#include \"file.h\"\n"
|
||||
"\n"
|
||||
"C::C()\n"
|
||||
"{@\n"
|
||||
"}\n" // Line 5
|
||||
"\n"
|
||||
"int C::function()\n"
|
||||
"{\n"
|
||||
" return 1 + 1;\n"
|
||||
"}\n" // Line 10
|
||||
);
|
||||
|
||||
QTest::newRow("fromDestructorDeclarationSymbol") << _(
|
||||
"class C\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" @C();\n"
|
||||
" int function();\n" // Line 5
|
||||
"};\n"
|
||||
) << _(
|
||||
"#include \"file.h\"\n"
|
||||
"\n"
|
||||
"C::$C()\n"
|
||||
"{\n"
|
||||
"}\n" // Line 5
|
||||
"\n"
|
||||
"int C::function()\n"
|
||||
"{\n"
|
||||
" return 1 + 1;\n"
|
||||
"}\n" // Line 10
|
||||
);
|
||||
|
||||
QTest::newRow("fromDestructorDefinitionSymbol") << _(
|
||||
"class C\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" ~$C();\n"
|
||||
" int function();\n"
|
||||
"};\n"
|
||||
) << _(
|
||||
"#include \"file.h\"\n"
|
||||
"\n"
|
||||
"C::@~C()\n"
|
||||
"{\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"int C::function()\n"
|
||||
"{\n"
|
||||
" return 1 + 1;\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
QTest::newRow("fromDestructorBody") << _(
|
||||
"class C\n"
|
||||
"{\n"
|
||||
"public:\n"
|
||||
" ~$C();\n"
|
||||
" int function();\n"
|
||||
"};\n"
|
||||
) << _(
|
||||
"#include \"file.h\"\n"
|
||||
"\n"
|
||||
"C::~C()\n"
|
||||
"{@\n"
|
||||
"}\n" // Line 5
|
||||
"\n"
|
||||
"int C::function()\n"
|
||||
"{\n"
|
||||
" return 1 + 1;\n"
|
||||
"}\n" // Line 10
|
||||
);
|
||||
|
||||
QTest::newRow("fromReturnType") << _(
|
||||
"class C\n"
|
||||
"{\n"
|
||||
|
@@ -796,6 +796,83 @@ void FollowSymbolUnderCursor::findLink(
|
||||
processLinkCallback(Link());
|
||||
}
|
||||
|
||||
void FollowSymbolUnderCursor::switchDeclDef(
|
||||
const CursorInEditor &data,
|
||||
Utils::ProcessLinkCallback &&processLinkCallback,
|
||||
const CPlusPlus::Snapshot &snapshot,
|
||||
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||
SymbolFinder *symbolFinder)
|
||||
{
|
||||
if (!documentFromSemanticInfo) {
|
||||
processLinkCallback({});
|
||||
return;
|
||||
}
|
||||
|
||||
// Find function declaration or definition under cursor
|
||||
Function *functionDefinitionSymbol = nullptr;
|
||||
Symbol *functionDeclarationSymbol = nullptr;
|
||||
Symbol *declarationSymbol = nullptr;
|
||||
|
||||
ASTPath astPathFinder(documentFromSemanticInfo);
|
||||
const QList<AST *> astPath = astPathFinder(data.cursor());
|
||||
|
||||
for (AST *ast : astPath) {
|
||||
if (FunctionDefinitionAST *functionDefinitionAST = ast->asFunctionDefinition()) {
|
||||
if ((functionDefinitionSymbol = functionDefinitionAST->symbol))
|
||||
break; // Function definition found!
|
||||
} else if (SimpleDeclarationAST *simpleDeclaration = ast->asSimpleDeclaration()) {
|
||||
if (List<Symbol *> *symbols = simpleDeclaration->symbols) {
|
||||
if (Symbol *symbol = symbols->value) {
|
||||
if (symbol->isDeclaration()) {
|
||||
declarationSymbol = symbol;
|
||||
if (symbol->type()->isFunctionType()) {
|
||||
functionDeclarationSymbol = symbol;
|
||||
break; // Function declaration found!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Link to function definition/declaration
|
||||
Utils::Link symbolLink;
|
||||
if (functionDeclarationSymbol) {
|
||||
Symbol *symbol = symbolFinder->findMatchingDefinition(functionDeclarationSymbol, snapshot);
|
||||
if (symbol)
|
||||
symbolLink = symbol->toLink();
|
||||
} else if (declarationSymbol) {
|
||||
Symbol *symbol = symbolFinder->findMatchingVarDefinition(declarationSymbol, snapshot);
|
||||
if (symbol)
|
||||
symbolLink = symbol->toLink();
|
||||
} else if (functionDefinitionSymbol) {
|
||||
LookupContext context(documentFromSemanticInfo, snapshot);
|
||||
ClassOrNamespace *binding = context.lookupType(functionDefinitionSymbol);
|
||||
const QList<LookupItem> declarations
|
||||
= context.lookup(functionDefinitionSymbol->name(),
|
||||
functionDefinitionSymbol->enclosingScope());
|
||||
|
||||
QList<Symbol *> best;
|
||||
foreach (const LookupItem &r, declarations) {
|
||||
if (Symbol *decl = r.declaration()) {
|
||||
if (Function *funTy = decl->type()->asFunctionType()) {
|
||||
if (funTy->match(functionDefinitionSymbol)) {
|
||||
if (decl != functionDefinitionSymbol && binding == r.binding())
|
||||
best.prepend(decl);
|
||||
else
|
||||
best.append(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best.isEmpty())
|
||||
return;
|
||||
symbolLink = best.first()->toLink();
|
||||
}
|
||||
processLinkCallback(symbolLink);
|
||||
}
|
||||
|
||||
QSharedPointer<VirtualFunctionAssistProvider> FollowSymbolUnderCursor::virtualFunctionAssistProvider()
|
||||
{
|
||||
return m_virtualFunctionAssistProvider;
|
||||
|
@@ -44,6 +44,12 @@ public:
|
||||
CppTools::SymbolFinder *symbolFinder,
|
||||
bool inNextSplit) override;
|
||||
|
||||
void switchDeclDef(const CursorInEditor &data,
|
||||
Utils::ProcessLinkCallback &&processLinkCallback,
|
||||
const CPlusPlus::Snapshot &snapshot,
|
||||
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||
SymbolFinder *symbolFinder) override;
|
||||
|
||||
QSharedPointer<VirtualFunctionAssistProvider> virtualFunctionAssistProvider();
|
||||
void setVirtualFunctionAssistProvider(
|
||||
const QSharedPointer<VirtualFunctionAssistProvider> &provider);
|
||||
|
@@ -472,6 +472,11 @@ RefactoringEngineInterface *CppModelManager::builtinRefactoringEngine()
|
||||
return instance()->d->m_refactoringEngines.value(RefactoringEngineType::BuiltIn);
|
||||
}
|
||||
|
||||
FollowSymbolInterface &CppModelManager::builtinFollowSymbol()
|
||||
{
|
||||
return instance()->d->m_builtinModelManagerSupport->followSymbolInterface();
|
||||
}
|
||||
|
||||
template<class FilterClass>
|
||||
static void setFilter(std::unique_ptr<FilterClass> &filter,
|
||||
std::unique_ptr<FilterClass> &&newFilter)
|
||||
|
@@ -218,6 +218,7 @@ public:
|
||||
RefactoringEngineInterface *refactoringEngine);
|
||||
static void removeRefactoringEngine(RefactoringEngineType type);
|
||||
static RefactoringEngineInterface *builtinRefactoringEngine();
|
||||
static FollowSymbolInterface &builtinFollowSymbol();
|
||||
|
||||
void setLocatorFilter(std::unique_ptr<Core::ILocatorFilter> &&filter);
|
||||
void setClassesFilter(std::unique_ptr<Core::ILocatorFilter> &&filter);
|
||||
|
@@ -49,6 +49,11 @@ public:
|
||||
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||
SymbolFinder *symbolFinder,
|
||||
bool inNextSplit) = 0;
|
||||
virtual void switchDeclDef(const CursorInEditor &data,
|
||||
Utils::ProcessLinkCallback &&processLinkCallback,
|
||||
const CPlusPlus::Snapshot &snapshot,
|
||||
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
|
||||
SymbolFinder *symbolFinder) = 0;
|
||||
};
|
||||
|
||||
} // namespace CppTools
|
||||
|
Reference in New Issue
Block a user