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 {
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() << ")";

View File

@@ -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);

View File

@@ -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<int>(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<CppTools::SymbolInfo> futureInterface = m_followTable.take(ticket);

View File

@@ -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,

View File

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

View File

@@ -146,7 +146,7 @@ static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line,
return tokenIndex;
}
SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu,
FollowSymbolResult FollowSymbol::followSymbol(CXTranslationUnit tu,
const Cursor &fullCursor,
uint line,
uint column)
@@ -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();

View File

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

View File

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

View File

@@ -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<FullTokenInfo> 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;

View File

@@ -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);
}

View File

@@ -32,6 +32,7 @@
#include <clangdocuments.h>
#include <clangtranslationunit.h>
#include <fixitcontainer.h>
#include <followsymbolmessage.h>
#include <projectpart.h>
#include <projects.h>
#include <sourcelocationcontainer.h>
@@ -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);
}

View File

@@ -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;

View File

@@ -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);