diff --git a/src/libs/clangsupport/followsymbolmessage.cpp b/src/libs/clangsupport/followsymbolmessage.cpp index 93a37b16a0a..22e77ee6d41 100644 --- a/src/libs/clangsupport/followsymbolmessage.cpp +++ b/src/libs/clangsupport/followsymbolmessage.cpp @@ -29,12 +29,23 @@ namespace ClangBackEnd { +QDebug operator<<(QDebug debug, const FollowSymbolResult &result) +{ + debug.nospace() << "FollowSymbolResult(" + << result.range + << ", " << result.isPureDeclarationForUsage; + + debug.nospace() << ")"; + + return debug; +} + QDebug operator<<(QDebug debug, const FollowSymbolMessage &message) { debug.nospace() << "FollowSymbolMessage(" << message.fileContainer << ", " << message.ticketNumber - << ", " << message.sourceRange; + << ", " << message.result; debug.nospace() << ")"; diff --git a/src/libs/clangsupport/followsymbolmessage.h b/src/libs/clangsupport/followsymbolmessage.h index 80b62628fb3..ec113825aeb 100644 --- a/src/libs/clangsupport/followsymbolmessage.h +++ b/src/libs/clangsupport/followsymbolmessage.h @@ -33,15 +33,53 @@ namespace ClangBackEnd { +class FollowSymbolResult +{ +public: + FollowSymbolResult() = default; + FollowSymbolResult(SourceRangeContainer range) + : range(std::move(range)) + {} + FollowSymbolResult(SourceRangeContainer range, bool isPureDeclarationForUsage) + : range(std::move(range)) + , isPureDeclarationForUsage(isPureDeclarationForUsage) + {} + + friend QDataStream &operator<<(QDataStream &out, const FollowSymbolResult &container) + { + out << container.range; + out << container.isPureDeclarationForUsage; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, FollowSymbolResult &container) + { + in >> container.range; + in >> container.isPureDeclarationForUsage; + + return in; + } + + friend bool operator==(const FollowSymbolResult &first, const FollowSymbolResult &second) + { + return first.range == second.range + && first.isPureDeclarationForUsage == second.isPureDeclarationForUsage; + } + + SourceRangeContainer range; + bool isPureDeclarationForUsage = false; +}; + class FollowSymbolMessage { public: FollowSymbolMessage() = default; FollowSymbolMessage(const FileContainer &fileContainer, - const SourceRangeContainer &range, + const FollowSymbolResult &result, quint64 ticketNumber) : fileContainer(fileContainer) - , sourceRange(range) + , result(result) , ticketNumber(ticketNumber) { } @@ -49,7 +87,7 @@ public: friend QDataStream &operator<<(QDataStream &out, const FollowSymbolMessage &message) { out << message.fileContainer; - out << message.sourceRange; + out << message.result; out << message.ticketNumber; return out; } @@ -57,7 +95,7 @@ public: friend QDataStream &operator>>(QDataStream &in, FollowSymbolMessage &message) { in >> message.fileContainer; - in >> message.sourceRange; + in >> message.result; in >> message.ticketNumber; return in; } @@ -66,15 +104,16 @@ public: { return first.ticketNumber == second.ticketNumber && first.fileContainer == second.fileContainer - && first.sourceRange == second.sourceRange; + && first.result == second.result; } public: FileContainer fileContainer; - SourceRangeContainer sourceRange; + FollowSymbolResult result; quint64 ticketNumber = 0; }; +CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FollowSymbolResult &result); CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FollowSymbolMessage &message); DECLARE_MESSAGE(FollowSymbolMessage); diff --git a/src/plugins/clangcodemodel/clangbackendreceiver.cpp b/src/plugins/clangcodemodel/clangbackendreceiver.cpp index 6cb6bafea12..b957ff1b08e 100644 --- a/src/plugins/clangcodemodel/clangbackendreceiver.cpp +++ b/src/plugins/clangcodemodel/clangbackendreceiver.cpp @@ -255,7 +255,7 @@ static CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message) { CppTools::SymbolInfo result; - const SourceRangeContainer &range = message.sourceRange; + const SourceRangeContainer &range = message.result.range; const SourceLocationContainer &start = range.start; const SourceLocationContainer &end = range.end; @@ -265,6 +265,8 @@ CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message) result.endColumn = static_cast(end.column); result.fileName = start.filePath; + result.isPureDeclarationForUsage = message.result.isPureDeclarationForUsage; + return result; } @@ -354,7 +356,7 @@ void BackendReceiver::tooltip(const ToolTipMessage &message) void BackendReceiver::followSymbol(const ClangBackEnd::FollowSymbolMessage &message) { qCDebugIpc() << "FollowSymbolMessage with" - << message.sourceRange << "range"; + << message.result; const quint64 ticket = message.ticketNumber; QFutureInterface futureInterface = m_followTable.take(ticket); diff --git a/src/plugins/clangcodemodel/clangfollowsymbol.cpp b/src/plugins/clangcodemodel/clangfollowsymbol.cpp index 2876055706e..e1f33bdf854 100644 --- a/src/plugins/clangcodemodel/clangfollowsymbol.cpp +++ b/src/plugins/clangcodemodel/clangfollowsymbol.cpp @@ -140,6 +140,19 @@ static Utils::Link linkAtCursor(const QTextCursor &cursor, return Link(); } +static ::Utils::ProcessLinkCallback extendedCallback(::Utils::ProcessLinkCallback &&callback, + const CppTools::SymbolInfo &result) +{ + // If globalFollowSymbol finds nothing follow to the declaration. + return [original_callback = std::move(callback), result](const ::Utils::Link &link) { + if (!link.hasValidTarget() && result.isPureDeclarationForUsage) { + return original_callback(::Utils::Link(result.fileName, result.startLine, + result.startColumn - 1)); + } + return original_callback(link); + }; +} + void ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data, ::Utils::ProcessLinkCallback &&processLinkCallback, bool resolveTarget, @@ -185,11 +198,11 @@ void ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data, return callback(Utils::Link()); CppTools::SymbolInfo result = m_watcher->result(); // We did not fail but the result is empty - if (result.fileName.isEmpty()) { + if (result.fileName.isEmpty() || result.isPureDeclarationForUsage) { const CppTools::RefactoringEngineInterface &refactoringEngine = *CppTools::CppModelManager::instance(); refactoringEngine.globalFollowSymbol(data, - std::move(callback), + extendedCallback(std::move(callback), result), snapshot, documentFromSemanticInfo, symbolFinder, diff --git a/src/plugins/cpptools/cppsymbolinfo.h b/src/plugins/cpptools/cppsymbolinfo.h index dcd00dd3c21..38edec11b3c 100644 --- a/src/plugins/cpptools/cppsymbolinfo.h +++ b/src/plugins/cpptools/cppsymbolinfo.h @@ -39,6 +39,7 @@ public: int endLine = 0; int endColumn = 0; QString fileName; + bool isPureDeclarationForUsage = false; }; } // namespace CppTools diff --git a/src/tools/clangbackend/source/clangfollowsymbol.cpp b/src/tools/clangbackend/source/clangfollowsymbol.cpp index 2d8b7004ebe..a0a25182f16 100644 --- a/src/tools/clangbackend/source/clangfollowsymbol.cpp +++ b/src/tools/clangbackend/source/clangfollowsymbol.cpp @@ -146,10 +146,10 @@ static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line, return tokenIndex; } -SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu, - const Cursor &fullCursor, - uint line, - uint column) +FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu, + const Cursor &fullCursor, + uint line, + uint column) { std::unique_ptr tokens(new Tokens(fullCursor)); @@ -175,7 +175,7 @@ SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu, CXFile file = clang_getIncludedFile(cursors[tokenIndex]); const ClangString filename(clang_getFileName(file)); const SourceLocation loc(tu, filename, 1, 1); - return SourceRange(loc, loc); + return SourceRangeContainer(SourceRange(loc, loc)); } // For definitions we can always find a declaration in current TU @@ -185,12 +185,16 @@ SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu, if (!cursor.isDeclaration()) { // This is the symbol usage // We want to return definition + FollowSymbolResult result; cursor = cursor.referenced(); - if (cursor.isNull() || !cursor.isDefinition()) { - // We can't find definition in this TU + if (cursor.isNull()) return SourceRangeContainer(); + if (!cursor.isDefinition()) { + // We can't find definition in this TU + result.isPureDeclarationForUsage = true; } - return extractMatchingTokenRange(cursor, tokenSpelling); + result.range = extractMatchingTokenRange(cursor, tokenSpelling); + return result; } cursor = cursor.definition(); diff --git a/src/tools/clangbackend/source/clangfollowsymbol.h b/src/tools/clangbackend/source/clangfollowsymbol.h index 07db59a836f..7c5469ef665 100644 --- a/src/tools/clangbackend/source/clangfollowsymbol.h +++ b/src/tools/clangbackend/source/clangfollowsymbol.h @@ -33,17 +33,18 @@ class Utf8String; namespace ClangBackEnd { -class Cursor; -class SourceRangeContainer; class CommandLineArguments; +class Cursor; +class FollowSymbolResult; +class SourceRangeContainer; class FollowSymbol { public: - static SourceRangeContainer followSymbol(CXTranslationUnit tu, - const Cursor &fullCursor, - uint line, - uint column); + static FollowSymbolResult followSymbol(CXTranslationUnit tu, + const Cursor &fullCursor, + uint line, + uint column); }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/source/clangfollowsymboljob.h b/src/tools/clangbackend/source/clangfollowsymboljob.h index 3a8741db1c6..5e625f97d49 100644 --- a/src/tools/clangbackend/source/clangfollowsymboljob.h +++ b/src/tools/clangbackend/source/clangfollowsymboljob.h @@ -27,14 +27,15 @@ #include "clangdocumentjob.h" +#include #include namespace ClangBackEnd { -class FollowSymbolJob : public DocumentJob +class FollowSymbolJob : public DocumentJob { public: - using AsyncResult = SourceRangeContainer; + using AsyncResult = FollowSymbolResult; AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; diff --git a/src/tools/clangbackend/source/clangtranslationunit.cpp b/src/tools/clangbackend/source/clangtranslationunit.cpp index f0bbc789347..4720f657918 100644 --- a/src/tools/clangbackend/source/clangtranslationunit.cpp +++ b/src/tools/clangbackend/source/clangtranslationunit.cpp @@ -269,7 +269,7 @@ void TranslationUnit::extractDiagnostics(DiagnosticContainer &firstHeaderErrorDi } } -SourceRangeContainer TranslationUnit::followSymbol(uint line, uint column) const +FollowSymbolResult TranslationUnit::followSymbol(uint line, uint column) const { return FollowSymbol::followSymbol(m_cxTranslationUnit, cursorAt(line, column), line, column); } diff --git a/src/tools/clangbackend/source/clangtranslationunit.h b/src/tools/clangbackend/source/clangtranslationunit.h index 70df60f5050..175ba2eb584 100644 --- a/src/tools/clangbackend/source/clangtranslationunit.h +++ b/src/tools/clangbackend/source/clangtranslationunit.h @@ -37,6 +37,7 @@ namespace ClangBackEnd { class Cursor; class DiagnosticContainer; class DiagnosticSet; +class FollowSymbolResult; class ReferencesResult; class SkippedSourceRanges; class SourceLocation; @@ -108,7 +109,7 @@ public: TokenProcessor fullTokenInfosInRange(const SourceRange &range) const; SkippedSourceRanges skippedSourceRanges() const; - SourceRangeContainer followSymbol(uint line, uint column) const; + FollowSymbolResult followSymbol(uint line, uint column) const; private: const Utf8String m_id; diff --git a/tests/unit/unittest/clangcodemodelserver-test.cpp b/tests/unit/unittest/clangcodemodelserver-test.cpp index ebcb5dd3d3e..7f88681f320 100644 --- a/tests/unit/unittest/clangcodemodelserver-test.cpp +++ b/tests/unit/unittest/clangcodemodelserver-test.cpp @@ -630,14 +630,12 @@ void ClangCodeModelServer::expectReferences() void ClangCodeModelServer::expectFollowSymbol() { - const ClangBackEnd::SourceRangeContainer classDefinition{ - {filePathC, 40, 7}, - {filePathC, 40, 10} - }; + const ClangBackEnd::FollowSymbolResult classDefinition + = ClangBackEnd::SourceRangeContainer({filePathC, 40, 7}, {filePathC, 40, 10}); EXPECT_CALL(mockClangCodeModelClient, followSymbol( - Field(&FollowSymbolMessage::sourceRange, + Field(&FollowSymbolMessage::result, Eq(classDefinition)))) .Times(1); } diff --git a/tests/unit/unittest/clangfollowsymbol-test.cpp b/tests/unit/unittest/clangfollowsymbol-test.cpp index f42e8e63993..9df7349306c 100644 --- a/tests/unit/unittest/clangfollowsymbol-test.cpp +++ b/tests/unit/unittest/clangfollowsymbol-test.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ using ::ClangBackEnd::Document; using ::ClangBackEnd::UnsavedFiles; using ::ClangBackEnd::ReferencesResult; using ::ClangBackEnd::SourceRangeContainer; +using ::ClangBackEnd::FollowSymbolResult; namespace { const Utf8String sourceFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_main.cpp"); @@ -131,12 +133,12 @@ public: class FollowSymbol : public ::testing::Test { protected: - SourceRangeContainer followSymbol(uint line, uint column) + FollowSymbolResult followSymbol(uint line, uint column) { return document.translationUnit().followSymbol(line, column); } - SourceRangeContainer followHeaderSymbol(uint line, uint column) + FollowSymbolResult followHeaderSymbol(uint line, uint column) { return headerDocument.translationUnit().followSymbol(line, column); } diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index c3e02240fe4..3b1a761a80c 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -237,12 +237,22 @@ std::ostream &operator<<(std::ostream &os, const RegisterProjectPartsForEditorMe return os; } +std::ostream &operator<<(std::ostream &os, const FollowSymbolResult &result) +{ + os << "(" + << result.range + << ", " << result.isPureDeclarationForUsage + << ")"; + + return os; +} + std::ostream &operator<<(std::ostream &os, const FollowSymbolMessage &message) { os << "(" << message.fileContainer << ", " << message.ticketNumber << ", " - << message.sourceRange << ", " + << message.result << ", " << ")"; return os; diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 6404764544b..d809b18b6e6 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -105,6 +105,7 @@ class EchoMessage; class DocumentAnnotationsChangedMessage; class ReferencesMessage; class ToolTipMessage; +class FollowSymbolResult; class FollowSymbolMessage; class CompleteCodeMessage; class EndMessage; @@ -177,6 +178,7 @@ std::ostream &operator<<(std::ostream &out, const EchoMessage &message); std::ostream &operator<<(std::ostream &out, const DocumentAnnotationsChangedMessage &message); std::ostream &operator<<(std::ostream &out, const ReferencesMessage &message); std::ostream &operator<<(std::ostream &out, const ToolTipMessage &message); +std::ostream &operator<<(std::ostream &out, const FollowSymbolResult &result); std::ostream &operator<<(std::ostream &out, const FollowSymbolMessage &message); std::ostream &operator<<(std::ostream &out, const CompleteCodeMessage &message); std::ostream &operator<<(std::ostream &out, const EndMessage &message);