Clang: Use follow symbol result from clang when global fails

When built-in code model fails to follow symbol under cursor
fall back to the clang result even if it only follows
to the decalration.

Change-Id: I22d8c5fee6ab7594b1d1b7ce8104414db28383c7
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-06-01 10:46:20 +02:00
parent 52bd5173fb
commit 4e4bd4909a
14 changed files with 122 additions and 37 deletions

View File

@@ -29,12 +29,23 @@
namespace ClangBackEnd { 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) QDebug operator<<(QDebug debug, const FollowSymbolMessage &message)
{ {
debug.nospace() << "FollowSymbolMessage(" debug.nospace() << "FollowSymbolMessage("
<< message.fileContainer << message.fileContainer
<< ", " << message.ticketNumber << ", " << message.ticketNumber
<< ", " << message.sourceRange; << ", " << message.result;
debug.nospace() << ")"; debug.nospace() << ")";

View File

@@ -33,15 +33,53 @@
namespace ClangBackEnd { 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 class FollowSymbolMessage
{ {
public: public:
FollowSymbolMessage() = default; FollowSymbolMessage() = default;
FollowSymbolMessage(const FileContainer &fileContainer, FollowSymbolMessage(const FileContainer &fileContainer,
const SourceRangeContainer &range, const FollowSymbolResult &result,
quint64 ticketNumber) quint64 ticketNumber)
: fileContainer(fileContainer) : fileContainer(fileContainer)
, sourceRange(range) , result(result)
, ticketNumber(ticketNumber) , ticketNumber(ticketNumber)
{ {
} }
@@ -49,7 +87,7 @@ public:
friend QDataStream &operator<<(QDataStream &out, const FollowSymbolMessage &message) friend QDataStream &operator<<(QDataStream &out, const FollowSymbolMessage &message)
{ {
out << message.fileContainer; out << message.fileContainer;
out << message.sourceRange; out << message.result;
out << message.ticketNumber; out << message.ticketNumber;
return out; return out;
} }
@@ -57,7 +95,7 @@ public:
friend QDataStream &operator>>(QDataStream &in, FollowSymbolMessage &message) friend QDataStream &operator>>(QDataStream &in, FollowSymbolMessage &message)
{ {
in >> message.fileContainer; in >> message.fileContainer;
in >> message.sourceRange; in >> message.result;
in >> message.ticketNumber; in >> message.ticketNumber;
return in; return in;
} }
@@ -66,15 +104,16 @@ public:
{ {
return first.ticketNumber == second.ticketNumber return first.ticketNumber == second.ticketNumber
&& first.fileContainer == second.fileContainer && first.fileContainer == second.fileContainer
&& first.sourceRange == second.sourceRange; && first.result == second.result;
} }
public: public:
FileContainer fileContainer; FileContainer fileContainer;
SourceRangeContainer sourceRange; FollowSymbolResult result;
quint64 ticketNumber = 0; quint64 ticketNumber = 0;
}; };
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FollowSymbolResult &result);
CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FollowSymbolMessage &message); CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const FollowSymbolMessage &message);
DECLARE_MESSAGE(FollowSymbolMessage); DECLARE_MESSAGE(FollowSymbolMessage);

View File

@@ -255,7 +255,7 @@ static
CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message) CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message)
{ {
CppTools::SymbolInfo result; CppTools::SymbolInfo result;
const SourceRangeContainer &range = message.sourceRange; const SourceRangeContainer &range = message.result.range;
const SourceLocationContainer &start = range.start; const SourceLocationContainer &start = range.start;
const SourceLocationContainer &end = range.end; const SourceLocationContainer &end = range.end;
@@ -265,6 +265,8 @@ CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message)
result.endColumn = static_cast<int>(end.column); result.endColumn = static_cast<int>(end.column);
result.fileName = start.filePath; result.fileName = start.filePath;
result.isPureDeclarationForUsage = message.result.isPureDeclarationForUsage;
return result; return result;
} }
@@ -354,7 +356,7 @@ void BackendReceiver::tooltip(const ToolTipMessage &message)
void BackendReceiver::followSymbol(const ClangBackEnd::FollowSymbolMessage &message) void BackendReceiver::followSymbol(const ClangBackEnd::FollowSymbolMessage &message)
{ {
qCDebugIpc() << "FollowSymbolMessage with" qCDebugIpc() << "FollowSymbolMessage with"
<< message.sourceRange << "range"; << message.result;
const quint64 ticket = message.ticketNumber; const quint64 ticket = message.ticketNumber;
QFutureInterface<CppTools::SymbolInfo> futureInterface = m_followTable.take(ticket); QFutureInterface<CppTools::SymbolInfo> futureInterface = m_followTable.take(ticket);

View File

@@ -140,6 +140,19 @@ static Utils::Link linkAtCursor(const QTextCursor &cursor,
return Link(); 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, void ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
::Utils::ProcessLinkCallback &&processLinkCallback, ::Utils::ProcessLinkCallback &&processLinkCallback,
bool resolveTarget, bool resolveTarget,
@@ -185,11 +198,11 @@ void ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
return callback(Utils::Link()); return callback(Utils::Link());
CppTools::SymbolInfo result = m_watcher->result(); CppTools::SymbolInfo result = m_watcher->result();
// We did not fail but the result is empty // We did not fail but the result is empty
if (result.fileName.isEmpty()) { if (result.fileName.isEmpty() || result.isPureDeclarationForUsage) {
const CppTools::RefactoringEngineInterface &refactoringEngine const CppTools::RefactoringEngineInterface &refactoringEngine
= *CppTools::CppModelManager::instance(); = *CppTools::CppModelManager::instance();
refactoringEngine.globalFollowSymbol(data, refactoringEngine.globalFollowSymbol(data,
std::move(callback), extendedCallback(std::move(callback), result),
snapshot, snapshot,
documentFromSemanticInfo, documentFromSemanticInfo,
symbolFinder, symbolFinder,

View File

@@ -39,6 +39,7 @@ public:
int endLine = 0; int endLine = 0;
int endColumn = 0; int endColumn = 0;
QString fileName; QString fileName;
bool isPureDeclarationForUsage = false;
}; };
} // namespace CppTools } // namespace CppTools

View File

@@ -146,10 +146,10 @@ static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line,
return tokenIndex; return tokenIndex;
} }
SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu, FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu,
const Cursor &fullCursor, const Cursor &fullCursor,
uint line, uint line,
uint column) uint column)
{ {
std::unique_ptr<Tokens> tokens(new Tokens(fullCursor)); std::unique_ptr<Tokens> tokens(new Tokens(fullCursor));
@@ -175,7 +175,7 @@ SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu,
CXFile file = clang_getIncludedFile(cursors[tokenIndex]); CXFile file = clang_getIncludedFile(cursors[tokenIndex]);
const ClangString filename(clang_getFileName(file)); const ClangString filename(clang_getFileName(file));
const SourceLocation loc(tu, filename, 1, 1); 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 // For definitions we can always find a declaration in current TU
@@ -185,12 +185,16 @@ SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu,
if (!cursor.isDeclaration()) { if (!cursor.isDeclaration()) {
// This is the symbol usage // This is the symbol usage
// We want to return definition // We want to return definition
FollowSymbolResult result;
cursor = cursor.referenced(); cursor = cursor.referenced();
if (cursor.isNull() || !cursor.isDefinition()) { if (cursor.isNull())
// We can't find definition in this TU
return SourceRangeContainer(); 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(); cursor = cursor.definition();

View File

@@ -33,17 +33,18 @@ class Utf8String;
namespace ClangBackEnd { namespace ClangBackEnd {
class Cursor;
class SourceRangeContainer;
class CommandLineArguments; class CommandLineArguments;
class Cursor;
class FollowSymbolResult;
class SourceRangeContainer;
class FollowSymbol class FollowSymbol
{ {
public: public:
static SourceRangeContainer followSymbol(CXTranslationUnit tu, static FollowSymbolResult followSymbol(CXTranslationUnit tu,
const Cursor &fullCursor, const Cursor &fullCursor,
uint line, uint line,
uint column); uint column);
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -27,14 +27,15 @@
#include "clangdocumentjob.h" #include "clangdocumentjob.h"
#include <clangsupport/followsymbolmessage.h>
#include <clangsupport/sourcerangecontainer.h> #include <clangsupport/sourcerangecontainer.h>
namespace ClangBackEnd { namespace ClangBackEnd {
class FollowSymbolJob : public DocumentJob<SourceRangeContainer> class FollowSymbolJob : public DocumentJob<FollowSymbolResult>
{ {
public: public:
using AsyncResult = SourceRangeContainer; using AsyncResult = FollowSymbolResult;
AsyncPrepareResult prepareAsyncRun() override; AsyncPrepareResult prepareAsyncRun() override;
void finalizeAsyncRun() override; void finalizeAsyncRun() override;

View File

@@ -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); return FollowSymbol::followSymbol(m_cxTranslationUnit, cursorAt(line, column), line, column);
} }

View File

@@ -37,6 +37,7 @@ namespace ClangBackEnd {
class Cursor; class Cursor;
class DiagnosticContainer; class DiagnosticContainer;
class DiagnosticSet; class DiagnosticSet;
class FollowSymbolResult;
class ReferencesResult; class ReferencesResult;
class SkippedSourceRanges; class SkippedSourceRanges;
class SourceLocation; class SourceLocation;
@@ -108,7 +109,7 @@ public:
TokenProcessor<FullTokenInfo> fullTokenInfosInRange(const SourceRange &range) const; TokenProcessor<FullTokenInfo> fullTokenInfosInRange(const SourceRange &range) const;
SkippedSourceRanges skippedSourceRanges() const; SkippedSourceRanges skippedSourceRanges() const;
SourceRangeContainer followSymbol(uint line, uint column) const; FollowSymbolResult followSymbol(uint line, uint column) const;
private: private:
const Utf8String m_id; const Utf8String m_id;

View File

@@ -630,14 +630,12 @@ void ClangCodeModelServer::expectReferences()
void ClangCodeModelServer::expectFollowSymbol() void ClangCodeModelServer::expectFollowSymbol()
{ {
const ClangBackEnd::SourceRangeContainer classDefinition{ const ClangBackEnd::FollowSymbolResult classDefinition
{filePathC, 40, 7}, = ClangBackEnd::SourceRangeContainer({filePathC, 40, 7}, {filePathC, 40, 10});
{filePathC, 40, 10}
};
EXPECT_CALL(mockClangCodeModelClient, EXPECT_CALL(mockClangCodeModelClient,
followSymbol( followSymbol(
Field(&FollowSymbolMessage::sourceRange, Field(&FollowSymbolMessage::result,
Eq(classDefinition)))) Eq(classDefinition))))
.Times(1); .Times(1);
} }

View File

@@ -32,6 +32,7 @@
#include <clangdocuments.h> #include <clangdocuments.h>
#include <clangtranslationunit.h> #include <clangtranslationunit.h>
#include <fixitcontainer.h> #include <fixitcontainer.h>
#include <followsymbolmessage.h>
#include <projectpart.h> #include <projectpart.h>
#include <projects.h> #include <projects.h>
#include <sourcelocationcontainer.h> #include <sourcelocationcontainer.h>
@@ -55,6 +56,7 @@ using ::ClangBackEnd::Document;
using ::ClangBackEnd::UnsavedFiles; using ::ClangBackEnd::UnsavedFiles;
using ::ClangBackEnd::ReferencesResult; using ::ClangBackEnd::ReferencesResult;
using ::ClangBackEnd::SourceRangeContainer; using ::ClangBackEnd::SourceRangeContainer;
using ::ClangBackEnd::FollowSymbolResult;
namespace { namespace {
const Utf8String sourceFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_main.cpp"); const Utf8String sourceFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_main.cpp");
@@ -131,12 +133,12 @@ public:
class FollowSymbol : public ::testing::Test class FollowSymbol : public ::testing::Test
{ {
protected: protected:
SourceRangeContainer followSymbol(uint line, uint column) FollowSymbolResult followSymbol(uint line, uint column)
{ {
return document.translationUnit().followSymbol(line, 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); return headerDocument.translationUnit().followSymbol(line, column);
} }

View File

@@ -237,12 +237,22 @@ std::ostream &operator<<(std::ostream &os, const RegisterProjectPartsForEditorMe
return os; 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) std::ostream &operator<<(std::ostream &os, const FollowSymbolMessage &message)
{ {
os << "(" os << "("
<< message.fileContainer << ", " << message.fileContainer << ", "
<< message.ticketNumber << ", " << message.ticketNumber << ", "
<< message.sourceRange << ", " << message.result << ", "
<< ")"; << ")";
return os; return os;

View File

@@ -105,6 +105,7 @@ class EchoMessage;
class DocumentAnnotationsChangedMessage; class DocumentAnnotationsChangedMessage;
class ReferencesMessage; class ReferencesMessage;
class ToolTipMessage; class ToolTipMessage;
class FollowSymbolResult;
class FollowSymbolMessage; class FollowSymbolMessage;
class CompleteCodeMessage; class CompleteCodeMessage;
class EndMessage; 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 DocumentAnnotationsChangedMessage &message);
std::ostream &operator<<(std::ostream &out, const ReferencesMessage &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 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 FollowSymbolMessage &message);
std::ostream &operator<<(std::ostream &out, const CompleteCodeMessage &message); std::ostream &operator<<(std::ostream &out, const CompleteCodeMessage &message);
std::ostream &operator<<(std::ostream &out, const EndMessage &message); std::ostream &operator<<(std::ostream &out, const EndMessage &message);