Clang: add globalFollowSymbol to RefactoringEngine

Allows to follow outside of current TU.

Change-Id: Ieea2fd72bfdf6d60a988b40efcf2f41c5a71d045
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
Ivan Donchevskii
2017-10-05 09:54:21 +02:00
parent c760804102
commit 7a7123b1bc
27 changed files with 133 additions and 265 deletions

View File

@@ -36,7 +36,6 @@ QDebug operator<<(QDebug debug, const RequestFollowSymbolMessage &message)
debug.nospace() << "RequestFollowSymbolMessage("; debug.nospace() << "RequestFollowSymbolMessage(";
debug.nospace() << message.m_fileContainer << ", "; debug.nospace() << message.m_fileContainer << ", ";
debug.nospace() << message.m_dependentFiles << ", ";
debug.nospace() << message.m_ticketNumber << ", "; debug.nospace() << message.m_ticketNumber << ", ";
debug.nospace() << message.m_line << ", "; debug.nospace() << message.m_line << ", ";
debug.nospace() << message.m_column << ", "; debug.nospace() << message.m_column << ", ";

View File

@@ -38,14 +38,12 @@ class RequestFollowSymbolMessage
public: public:
RequestFollowSymbolMessage() = default; RequestFollowSymbolMessage() = default;
RequestFollowSymbolMessage(const FileContainer &fileContainer, RequestFollowSymbolMessage(const FileContainer &fileContainer,
const QVector<Utf8String> &dependentFiles,
quint32 line, quint32 line,
quint32 column) quint32 column)
: m_fileContainer(fileContainer) : m_fileContainer(fileContainer)
, m_ticketNumber(++ticketCounter) , m_ticketNumber(++ticketCounter)
, m_line(line) , m_line(line)
, m_column(column) , m_column(column)
, m_dependentFiles(dependentFiles)
{ {
} }
@@ -54,11 +52,6 @@ public:
return m_fileContainer; return m_fileContainer;
} }
const QVector<Utf8String> &dependentFiles() const
{
return m_dependentFiles;
}
quint32 line() const quint32 line() const
{ {
return m_line; return m_line;
@@ -77,7 +70,6 @@ public:
friend QDataStream &operator<<(QDataStream &out, const RequestFollowSymbolMessage &message) friend QDataStream &operator<<(QDataStream &out, const RequestFollowSymbolMessage &message)
{ {
out << message.m_fileContainer; out << message.m_fileContainer;
out << message.m_dependentFiles;
out << message.m_ticketNumber; out << message.m_ticketNumber;
out << message.m_line; out << message.m_line;
out << message.m_column; out << message.m_column;
@@ -88,7 +80,6 @@ public:
friend QDataStream &operator>>(QDataStream &in, RequestFollowSymbolMessage &message) friend QDataStream &operator>>(QDataStream &in, RequestFollowSymbolMessage &message)
{ {
in >> message.m_fileContainer; in >> message.m_fileContainer;
in >> message.m_dependentFiles;
in >> message.m_ticketNumber; in >> message.m_ticketNumber;
in >> message.m_line; in >> message.m_line;
in >> message.m_column; in >> message.m_column;
@@ -102,8 +93,7 @@ public:
return first.m_ticketNumber == second.m_ticketNumber return first.m_ticketNumber == second.m_ticketNumber
&& first.m_line == second.m_line && first.m_line == second.m_line
&& first.m_column == second.m_column && first.m_column == second.m_column
&& first.m_fileContainer == second.m_fileContainer && first.m_fileContainer == second.m_fileContainer;
&& first.m_dependentFiles == second.m_dependentFiles;
} }
friend CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const RequestFollowSymbolMessage &message); friend CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const RequestFollowSymbolMessage &message);
@@ -112,7 +102,6 @@ private:
quint64 m_ticketNumber = 0; quint64 m_ticketNumber = 0;
quint32 m_line = 0; quint32 m_line = 0;
quint32 m_column = 0; quint32 m_column = 0;
QVector<Utf8String> m_dependentFiles;
static CLANGSUPPORT_EXPORT quint64 ticketCounter; static CLANGSUPPORT_EXPORT quint64 ticketCounter;
}; };

View File

@@ -394,12 +394,10 @@ QFuture<CppTools::CursorInfo> BackendCommunicator::requestLocalReferences(
QFuture<CppTools::SymbolInfo> BackendCommunicator::requestFollowSymbol( QFuture<CppTools::SymbolInfo> BackendCommunicator::requestFollowSymbol(
const FileContainer &curFileContainer, const FileContainer &curFileContainer,
const QVector<Utf8String> &dependentFiles,
quint32 line, quint32 line,
quint32 column) quint32 column)
{ {
const RequestFollowSymbolMessage message(curFileContainer, const RequestFollowSymbolMessage message(curFileContainer,
dependentFiles,
line, line,
column); column);
m_sender->requestFollowSymbol(message); m_sender->requestFollowSymbol(message);

View File

@@ -83,7 +83,6 @@ public:
quint32 column, quint32 column,
QTextDocument *textDocument); QTextDocument *textDocument);
QFuture<CppTools::SymbolInfo> requestFollowSymbol(const FileContainer &curFileContainer, QFuture<CppTools::SymbolInfo> requestFollowSymbol(const FileContainer &curFileContainer,
const QVector<Utf8String> &dependentFiles,
quint32 line, quint32 line,
quint32 column); quint32 column);
void completeCode(ClangCompletionAssistProcessor *assistProcessor, const QString &filePath, void completeCode(ClangCompletionAssistProcessor *assistProcessor, const QString &filePath,

View File

@@ -367,50 +367,10 @@ QFuture<CppTools::CursorInfo> ClangEditorDocumentProcessor::requestLocalReferenc
textDocument()); textDocument());
} }
static QVector<Utf8String> prioritizeByBaseName(const QString &curPath,
const ::Utils::FileNameList &fileDeps)
{
QList<Utf8String> dependentFiles;
dependentFiles.reserve(fileDeps.size());
for (const ::Utils::FileName &dep: fileDeps)
dependentFiles.push_back(dep.toString());
const QString curFilename = QFileInfo(curPath).fileName();
if (CppTools::ProjectFile::isHeader(CppTools::ProjectFile::classify(curFilename))) {
const QString withoutExt = QFileInfo(curFilename).baseName();
int posToMove = 0;
// Move exact match to the first place and partial matches after it
for (int i = 0; i < dependentFiles.size(); ++i) {
const QString baseName = QFileInfo(dependentFiles[i]).baseName();
if (withoutExt == baseName) {
dependentFiles.move(i, 0);
posToMove++;
continue;
}
if (baseName.contains(withoutExt))
dependentFiles.move(i, posToMove++);
}
}
// Limit the number of scans (don't search for overrides)
if (dependentFiles.size() > 5)
dependentFiles.erase(dependentFiles.begin() + 5, dependentFiles.end());
return QVector<Utf8String>::fromList(dependentFiles);
}
QFuture<CppTools::SymbolInfo> QFuture<CppTools::SymbolInfo>
ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column) ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column)
{ {
QVector<Utf8String> dependentFiles;
CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
if (modelManager && !modelManager->projectPart(filePath()).isEmpty()) {
// This might be not so fast - index will change that
const ::Utils::FileNameList fileDeps
= modelManager->snapshot().filesDependingOn(filePath());
dependentFiles = prioritizeByBaseName(filePath(), fileDeps);
}
return m_communicator.requestFollowSymbol(simpleFileContainer(), return m_communicator.requestFollowSymbol(simpleFileContainer(),
dependentFiles,
static_cast<quint32>(line), static_cast<quint32>(line),
static_cast<quint32>(column)); static_cast<quint32>(column));
} }

View File

@@ -26,6 +26,7 @@
#include "clangeditordocumentprocessor.h" #include "clangeditordocumentprocessor.h"
#include "clangfollowsymbol.h" #include "clangfollowsymbol.h"
#include <cpptools/cppmodelmanager.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <clangsupport/tokeninfocontainer.h> #include <clangsupport/tokeninfocontainer.h>
@@ -94,10 +95,10 @@ static Utils::Link linkAtCursor(QTextCursor cursor, const QString &filePath, uin
Utils::Link ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data, Utils::Link ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
bool resolveTarget, bool resolveTarget,
const CPlusPlus::Snapshot &, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
CppTools::SymbolFinder *, CppTools::SymbolFinder *symbolFinder,
bool) bool inNextSplit)
{ {
int lineNumber = 0, positionInBlock = 0; int lineNumber = 0, positionInBlock = 0;
QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor()); QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor());
@@ -130,8 +131,12 @@ Utils::Link ClangFollowSymbol::findLink(const CppTools::CursorInEditor &data,
CppTools::SymbolInfo result = info.result(); CppTools::SymbolInfo result = info.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()) {
return Link(); const CppTools::RefactoringEngineInterface &refactoringEngine
= *CppTools::CppModelManager::instance();
return refactoringEngine.globalFollowSymbol(data, snapshot, documentFromSemanticInfo,
symbolFinder, inNextSplit);
}
return Link(result.fileName, result.startLine, result.startColumn - 1); return Link(result.fileName, result.startLine, result.startColumn - 1);
} }

View File

@@ -35,10 +35,10 @@ class ClangFollowSymbol : public CppTools::FollowSymbolInterface
public: public:
Link findLink(const CppTools::CursorInEditor &data, Link findLink(const CppTools::CursorInEditor &data,
bool resolveTarget, bool resolveTarget,
const CPlusPlus::Snapshot &, const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &, const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
CppTools::SymbolFinder *, CppTools::SymbolFinder *symbolFinder,
bool) override; bool inNextSplit) override;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -43,6 +43,12 @@ public:
void globalRename(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&, void globalRename(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&,
const QString &) override {} const QString &) override {}
void findUsages(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&) const override {} void findUsages(const CppTools::CursorInEditor &, CppTools::UsagesCallback &&) const override {}
Link globalFollowSymbol(const CppTools::CursorInEditor &, const CPlusPlus::Snapshot &,
const CPlusPlus::Document::Ptr &, CppTools::SymbolFinder *,
bool) const override
{
return Link();
}
}; };
} // namespace ClangRefactoring } // namespace ClangRefactoring

View File

@@ -35,6 +35,7 @@
#include <clangsupport/filepathcachinginterface.h> #include <clangsupport/filepathcachinginterface.h>
#include <utils/algorithm.h>
#include <utils/textutils.h> #include <utils/textutils.h>
#include <QTextCursor> #include <QTextCursor>
@@ -115,6 +116,24 @@ void RefactoringEngine::findUsages(const CppTools::CursorInEditor &data,
showUsagesCallback(locationsAt(data)); showUsagesCallback(locationsAt(data));
} }
RefactoringEngine::Link RefactoringEngine::globalFollowSymbol(const CppTools::CursorInEditor &data,
const CPlusPlus::Snapshot &,
const CPlusPlus::Document::Ptr &,
CppTools::SymbolFinder *,
bool) const
{
// TODO: replace that with specific followSymbol query
const CppTools::Usages usages = locationsAt(data);
CppTools::Usage usage = Utils::findOrDefault(usages, [&data](const CppTools::Usage &usage) {
// We've already searched in the current file, skip it.
if (usage.path == data.filePath().toString())
return false;
return true;
});
return Link(usage.path, usage.line, usage.column);
}
bool RefactoringEngine::isRefactoringEngineAvailable() const bool RefactoringEngine::isRefactoringEngineAvailable() const
{ {
return m_server.isAvailable(); return m_server.isAvailable();

View File

@@ -36,6 +36,8 @@ class RefactoringClientInterface;
class RefactoringServerInterface; class RefactoringServerInterface;
} }
namespace CppTools { class SymbolFinder; }
namespace ClangRefactoring { namespace ClangRefactoring {
class RefactoringEngine : public CppTools::RefactoringEngineInterface class RefactoringEngine : public CppTools::RefactoringEngineInterface
@@ -55,6 +57,11 @@ public:
const QString &) override; const QString &) override;
void findUsages(const CppTools::CursorInEditor &data, void findUsages(const CppTools::CursorInEditor &data,
CppTools::UsagesCallback &&showUsagesCallback) const override; CppTools::UsagesCallback &&showUsagesCallback) const override;
Link globalFollowSymbol(const CppTools::CursorInEditor &data,
const CPlusPlus::Snapshot &,
const CPlusPlus::Document::Ptr &,
CppTools::SymbolFinder *,
bool) const override;
bool isRefactoringEngineAvailable() const override; bool isRefactoringEngineAvailable() const override;
void setRefactoringEngineAvailable(bool isAvailable); void setRefactoringEngineAvailable(bool isAvailable);

View File

@@ -289,7 +289,7 @@ void CppModelManager::startLocalRenaming(const CursorInEditor &data,
CppTools::ProjectPart *projectPart, CppTools::ProjectPart *projectPart,
RenameCallback &&renameSymbolsCallback) RenameCallback &&renameSymbolsCallback)
{ {
RefactoringEngineInterface *engine = getRefactoringEngine(instance()->d->m_refactoringEngines, RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines,
false); false);
QTC_ASSERT(engine, return;); QTC_ASSERT(engine, return;);
engine->startLocalRenaming(data, projectPart, std::move(renameSymbolsCallback)); engine->startLocalRenaming(data, projectPart, std::move(renameSymbolsCallback));
@@ -298,7 +298,7 @@ void CppModelManager::startLocalRenaming(const CursorInEditor &data,
void CppModelManager::globalRename(const CursorInEditor &data, UsagesCallback &&renameCallback, void CppModelManager::globalRename(const CursorInEditor &data, UsagesCallback &&renameCallback,
const QString &replacement) const QString &replacement)
{ {
RefactoringEngineInterface *engine = getRefactoringEngine(instance()->d->m_refactoringEngines); RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines);
QTC_ASSERT(engine, return;); QTC_ASSERT(engine, return;);
engine->globalRename(data, std::move(renameCallback), replacement); engine->globalRename(data, std::move(renameCallback), replacement);
} }
@@ -306,11 +306,24 @@ void CppModelManager::globalRename(const CursorInEditor &data, UsagesCallback &&
void CppModelManager::findUsages(const CppTools::CursorInEditor &data, void CppModelManager::findUsages(const CppTools::CursorInEditor &data,
UsagesCallback &&showUsagesCallback) const UsagesCallback &&showUsagesCallback) const
{ {
RefactoringEngineInterface *engine = getRefactoringEngine(instance()->d->m_refactoringEngines); RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines);
QTC_ASSERT(engine, return;); QTC_ASSERT(engine, return;);
engine->findUsages(data, std::move(showUsagesCallback)); engine->findUsages(data, std::move(showUsagesCallback));
} }
CppModelManager::Link CppModelManager::globalFollowSymbol(
const CursorInEditor &data,
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder,
bool inNextSplit) const
{
RefactoringEngineInterface *engine = getRefactoringEngine(d->m_refactoringEngines);
QTC_ASSERT(engine, return Link(););
return engine->globalFollowSymbol(data, snapshot, documentFromSemanticInfo,
symbolFinder, inNextSplit);
}
void CppModelManager::addRefactoringEngine(RefactoringEngineType type, void CppModelManager::addRefactoringEngine(RefactoringEngineType type,
RefactoringEngineInterface *refactoringEngine) RefactoringEngineInterface *refactoringEngine)
{ {

View File

@@ -155,6 +155,11 @@ public:
const QString &replacement) final; const QString &replacement) final;
void findUsages(const CppTools::CursorInEditor &data, void findUsages(const CppTools::CursorInEditor &data,
UsagesCallback &&showUsagesCallback) const final; UsagesCallback &&showUsagesCallback) const final;
Link globalFollowSymbol(const CursorInEditor &data,
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder,
bool inNextSplit) const final;
void renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context, void renameUsages(CPlusPlus::Symbol *symbol, const CPlusPlus::LookupContext &context,
const QString &replacement = QString()); const QString &replacement = QString());

View File

@@ -28,6 +28,7 @@
#include "cpprefactoringengine.h" #include "cpprefactoringengine.h"
#include "cppsemanticinfo.h" #include "cppsemanticinfo.h"
#include "cpptoolsreuse.h" #include "cpptoolsreuse.h"
#include "cppfollowsymbolundercursor.h"
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
@@ -99,4 +100,16 @@ void CppRefactoringEngine::findUsages(const CursorInEditor &data,
} }
} }
CppRefactoringEngine::Link CppRefactoringEngine::globalFollowSymbol(
const CursorInEditor &data,
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder,
bool inNextSplit) const
{
FollowSymbolUnderCursor followSymbol;
return followSymbol.findLink(data, true, snapshot, documentFromSemanticInfo,
symbolFinder, inNextSplit);
}
} // namespace CppEditor } // namespace CppEditor

View File

@@ -38,6 +38,11 @@ public:
void globalRename(const CursorInEditor &data, UsagesCallback &&, void globalRename(const CursorInEditor &data, UsagesCallback &&,
const QString &replacement) override; const QString &replacement) override;
void findUsages(const CursorInEditor &data, UsagesCallback &&) const override; void findUsages(const CursorInEditor &data, UsagesCallback &&) const override;
Link globalFollowSymbol(const CursorInEditor &data,
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder,
bool inNextSplit) const override;
}; };
} // namespace CppEditor } // namespace CppEditor

View File

@@ -29,12 +29,15 @@
#include "cursorineditor.h" #include "cursorineditor.h"
#include "usages.h" #include "usages.h"
#include <utils/link.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/smallstring.h> #include <utils/smallstring.h>
#include <clangsupport/sourcelocationscontainer.h> #include <clangsupport/sourcelocationscontainer.h>
#include <clangsupport/refactoringclientinterface.h> #include <clangsupport/refactoringclientinterface.h>
#include <cplusplus/CppDocument.h>
namespace TextEditor { namespace TextEditor {
class TextEditorWidget; class TextEditorWidget;
} // namespace TextEditor } // namespace TextEditor
@@ -42,6 +45,7 @@ class TextEditorWidget;
namespace CppTools { namespace CppTools {
class ProjectPart; class ProjectPart;
class SymbolFinder;
enum class CallType enum class CallType
{ {
@@ -54,6 +58,7 @@ class CPPTOOLS_EXPORT RefactoringEngineInterface
{ {
public: public:
using RenameCallback = ClangBackEnd::RefactoringClientInterface::RenameCallback; using RenameCallback = ClangBackEnd::RefactoringClientInterface::RenameCallback;
using Link = Utils::Link;
virtual ~RefactoringEngineInterface() {} virtual ~RefactoringEngineInterface() {}
@@ -65,6 +70,11 @@ public:
const QString &replacement) = 0; const QString &replacement) = 0;
virtual void findUsages(const CppTools::CursorInEditor &data, virtual void findUsages(const CppTools::CursorInEditor &data,
UsagesCallback &&showUsagesCallback) const = 0; UsagesCallback &&showUsagesCallback) const = 0;
virtual Link globalFollowSymbol(const CursorInEditor &data,
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
SymbolFinder *symbolFinder,
bool inNextSplit) const = 0;
virtual bool isRefactoringEngineAvailable() const { return true; } virtual bool isRefactoringEngineAvailable() const { return true; }
}; };

View File

@@ -37,6 +37,7 @@ namespace CppTools {
class Usage class Usage
{ {
public: public:
Usage() {}
Usage(Utils::SmallStringView path, int line, int column) Usage(Utils::SmallStringView path, int line, int column)
: path(QString::fromUtf8(path.data(), int(path.size()))), : path(QString::fromUtf8(path.data(), int(path.size()))),
line(line), line(line),
@@ -52,8 +53,8 @@ public:
public: public:
QString path; QString path;
int line; int line = 0;
int column; int column = 0;
}; };
using Usages = std::vector<Usage>; using Usages = std::vector<Usage>;

View File

@@ -281,7 +281,6 @@ void ClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMessage
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::FollowSymbol); JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::FollowSymbol);
fillJobRequest(jobRequest, message); fillJobRequest(jobRequest, message);
jobRequest.dependentFiles = message.dependentFiles();
processor.addJob(jobRequest); processor.addJob(jobRequest);
processor.process(); processor.process();
} catch (const std::exception &exception) { } catch (const std::exception &exception) {

View File

@@ -133,47 +133,6 @@ static SourceRangeContainer extractMatchingTokenRange(const Cursor &cursor,
return SourceRangeContainer(); return SourceRangeContainer();
} }
static void handleDeclaration(CXClientData client_data, const CXIdxDeclInfo *declInfo)
{
if (!declInfo || !declInfo->isDefinition)
return;
const Cursor currentCursor(declInfo->cursor);
auto* data = reinterpret_cast<FollowSymbolData*>(client_data);
if (data->ready())
return;
if (data->usr() != currentCursor.canonical().unifiedSymbolResolution())
return;
QString str = Utf8String(currentCursor.displayName());
if (currentCursor.isFunctionLike() || currentCursor.isConstructorOrDestructor()) {
if (!data->isFunctionLike())
return;
str = str.mid(0, str.indexOf('('));
} else if (data->isFunctionLike()) {
return;
}
if (!str.endsWith(data->spelling()))
return;
const CXTranslationUnit tu = clang_Cursor_getTranslationUnit(declInfo->cursor);
Tokens tokens(currentCursor);
for (uint i = 0; i < tokens.tokenCount; ++i) {
Utf8String curSpelling = ClangString(clang_getTokenSpelling(tu, tokens.data[i]));
if (data->spelling() == curSpelling) {
if (data->isFunctionLike()
&& (i+1 >= tokens.tokenCount
|| !(ClangString(clang_getTokenSpelling(tu, tokens.data[i+1])) == "("))) {
continue;
}
data->setResult(SourceRange(clang_getTokenExtent(tu, tokens.data[i])));
data->setReady();
return;
}
}
}
static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line, uint column) static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line, uint column)
{ {
int tokenIndex = -1; int tokenIndex = -1;
@@ -187,90 +146,10 @@ static int getTokenIndex(CXTranslationUnit tu, const Tokens &tokens, uint line,
return tokenIndex; return tokenIndex;
} }
static IndexerCallbacks createIndexerCallbacks()
{
return {
[](CXClientData client_data, void *) {
auto* data = reinterpret_cast<FollowSymbolData*>(client_data);
return data->ready() ? 1 : 0;
},
[](CXClientData, CXDiagnosticSet, void *) {},
[](CXClientData, CXFile, void *) { return CXIdxClientFile(); },
[](CXClientData, const CXIdxIncludedFileInfo *) { return CXIdxClientFile(); },
[](CXClientData, const CXIdxImportedASTFileInfo *) { return CXIdxClientASTFile(); },
[](CXClientData, void *) { return CXIdxClientContainer(); },
handleDeclaration,
[](CXClientData, const CXIdxEntityRefInfo *) {}
};
}
static SourceRangeContainer followSymbolInDependentFiles(CXIndex index,
const Cursor &cursor,
const Utf8String &tokenSpelling,
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs)
{
int argsCount = 0;
if (currentArgs.data())
argsCount = currentArgs.count() - 1;
const Utf8String usr = cursor.canonical().unifiedSymbolResolution();
// ready is shared for all data in vector
std::atomic<bool> ready {false};
std::vector<FollowSymbolData> dataVector(
dependentFiles.size(),
FollowSymbolData(usr, tokenSpelling,
cursor.isFunctionLike() || cursor.isConstructorOrDestructor(),
ready));
std::vector<std::future<void>> indexFutures;
for (int i = 0; i < dependentFiles.size(); ++i) {
if (i > 0 && ready)
break;
indexFutures.emplace_back(std::async([&, i]() {
TIME_SCOPE_DURATION("Dependent file " + dependentFiles.at(i) + " indexer runner");
const CXIndexAction indexAction = clang_IndexAction_create(index);
IndexerCallbacks callbacks = createIndexerCallbacks();
clang_indexSourceFile(indexAction,
&dataVector[i],
&callbacks,
sizeof(callbacks),
CXIndexOpt_SkipParsedBodiesInSession
| CXIndexOpt_SuppressRedundantRefs
| CXIndexOpt_SuppressWarnings,
dependentFiles.at(i).constData(),
currentArgs.data(),
argsCount,
nullptr,
0,
nullptr,
CXTranslationUnit_SkipFunctionBodies
| CXTranslationUnit_KeepGoing);
clang_IndexAction_dispose(indexAction);
}));
}
for (const std::future<void> &future: indexFutures)
future.wait();
for (const FollowSymbolData &data: dataVector) {
if (!data.result().start().filePath().isEmpty()) {
return data.result();
}
}
return SourceRangeContainer();
}
SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu, SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu,
CXIndex index,
const Cursor &fullCursor, const Cursor &fullCursor,
uint line, uint line,
uint column, uint column)
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs)
{ {
std::unique_ptr<Tokens> tokens(new Tokens(fullCursor)); std::unique_ptr<Tokens> tokens(new Tokens(fullCursor));
@@ -303,35 +182,23 @@ SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu,
if (cursor.isDefinition()) if (cursor.isDefinition())
return extractMatchingTokenRange(cursor.canonical(), tokenSpelling); return extractMatchingTokenRange(cursor.canonical(), tokenSpelling);
SourceRangeContainer result;
if (!cursor.isDeclaration()) { if (!cursor.isDeclaration()) {
// This is the symbol usage // This is the symbol usage
// We want to return definition or at least declaration of this symbol // We want to return definition
const Cursor referencedCursor = cursor.referenced(); cursor = cursor.referenced();
if (referencedCursor.isNull() || referencedCursor == cursor) if (cursor.isNull() || !cursor.isDefinition()) {
// We can't find definition in this TU
return SourceRangeContainer(); return SourceRangeContainer();
result = extractMatchingTokenRange(referencedCursor, tokenSpelling); }
return extractMatchingTokenRange(cursor, tokenSpelling);
// We've already found what we need
if (referencedCursor.isDefinition())
return result;
cursor = referencedCursor;
} }
const Cursor definitionCursor = cursor.definition(); cursor = cursor.definition();
if (!definitionCursor.isNull() && definitionCursor != cursor) { // If we are able to find a definition in current TU
// If we are able to find a definition in current TU if (!cursor.isNull())
return extractMatchingTokenRange(definitionCursor, tokenSpelling); return extractMatchingTokenRange(cursor, tokenSpelling);
}
// Search for the definition in the dependent files return SourceRangeContainer();
SourceRangeContainer dependentFilesResult = followSymbolInDependentFiles(index,
cursor,
tokenSpelling,
dependentFiles,
currentArgs);
return dependentFilesResult.start().filePath().isEmpty() ?
result : dependentFilesResult;
} }
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -41,12 +41,9 @@ class FollowSymbol
{ {
public: public:
static SourceRangeContainer followSymbol(CXTranslationUnit tu, static SourceRangeContainer followSymbol(CXTranslationUnit tu,
CXIndex index,
const Cursor &fullCursor, const Cursor &fullCursor,
uint line, uint line,
uint column, uint column);
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs);
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -42,17 +42,12 @@ IAsyncJob::AsyncPrepareResult FollowSymbolJob::prepareAsyncRun()
const TranslationUnit translationUnit = *m_translationUnit; const TranslationUnit translationUnit = *m_translationUnit;
const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput();
const CommandLineArguments currentArgs(updateInput.filePath.constData(),
updateInput.projectArguments,
updateInput.fileArguments,
false);
const quint32 line = jobRequest.line; const quint32 line = jobRequest.line;
const quint32 column = jobRequest.column; const quint32 column = jobRequest.column;
const QVector<Utf8String> &dependentFiles = jobRequest.dependentFiles; setRunner([translationUnit, line, column]() {
setRunner([translationUnit, line, column, dependentFiles, currentArgs]() {
TIME_SCOPE_DURATION("FollowSymbolJobRunner"); TIME_SCOPE_DURATION("FollowSymbolJobRunner");
return translationUnit.followSymbol(line, column, dependentFiles, currentArgs); return translationUnit.followSymbol(line, column);
}); });
return AsyncPrepareResult{translationUnit.id()}; return AsyncPrepareResult{translationUnit.id()};

View File

@@ -117,7 +117,6 @@ public:
qint32 funcNameStartLine = -1; qint32 funcNameStartLine = -1;
qint32 funcNameStartColumn = -1; qint32 funcNameStartColumn = -1;
quint64 ticketNumber = 0; quint64 ticketNumber = 0;
Utf8StringVector dependentFiles;
bool localReferences = false; bool localReferences = false;
}; };

View File

@@ -238,13 +238,9 @@ void TranslationUnit::extractDiagnostics(DiagnosticContainer &firstHeaderErrorDi
} }
} }
SourceRangeContainer TranslationUnit::followSymbol(uint line, SourceRangeContainer TranslationUnit::followSymbol(uint line, uint column) const
uint column,
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs) const
{ {
return FollowSymbol::followSymbol(m_cxTranslationUnit, m_cxIndex, cursorAt(line, column), line, return FollowSymbol::followSymbol(m_cxTranslationUnit, cursorAt(line, column), line, column);
column, dependentFiles, currentArgs);
} }
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -100,10 +100,7 @@ public:
TokenInfos tokenInfosInRange(const SourceRange &range) const; TokenInfos tokenInfosInRange(const SourceRange &range) const;
SkippedSourceRanges skippedSourceRanges() const; SkippedSourceRanges skippedSourceRanges() const;
SourceRangeContainer followSymbol(uint line, SourceRangeContainer followSymbol(uint line, uint column) const;
uint column,
const QVector<Utf8String> &dependentFiles,
const CommandLineArguments &currentArgs) const;
private: private:
const Utf8String m_id; const Utf8String m_id;

View File

@@ -619,7 +619,7 @@ void ClangCodeModelServer::requestFollowSymbol(quint32 documentRevision)
{ {
const FileContainer fileContainer{filePathC, projectPartId, Utf8StringVector(), const FileContainer fileContainer{filePathC, projectPartId, Utf8StringVector(),
documentRevision}; documentRevision};
const RequestFollowSymbolMessage message{fileContainer, QVector<Utf8String>(), 43, 9}; const RequestFollowSymbolMessage message{fileContainer, 43, 9};
clangServer.requestFollowSymbol(message); clangServer.requestFollowSymbol(message);
} }

View File

@@ -133,23 +133,12 @@ class FollowSymbol : public ::testing::Test
protected: protected:
SourceRangeContainer followSymbol(uint line, uint column) SourceRangeContainer followSymbol(uint line, uint column)
{ {
ClangBackEnd::TranslationUnitUpdateInput updateInput = document.createUpdateInput(); return document.translationUnit().followSymbol(line, column);
const ClangBackEnd::CommandLineArguments currentArgs(updateInput.filePath.constData(),
updateInput.projectArguments,
updateInput.fileArguments,
false);
return document.translationUnit().followSymbol(line, column, deps, currentArgs);
} }
SourceRangeContainer followHeaderSymbol(uint line, uint column) SourceRangeContainer followHeaderSymbol(uint line, uint column)
{ {
ClangBackEnd::TranslationUnitUpdateInput updateInput return headerDocument.translationUnit().followSymbol(line, column);
= headerDocument.createUpdateInput();
const ClangBackEnd::CommandLineArguments currentArgs(updateInput.filePath.constData(),
updateInput.projectArguments,
updateInput.fileArguments,
false);
return headerDocument.translationUnit().followSymbol(line, column, deps, currentArgs);
} }
static void SetUpTestCase(); static void SetUpTestCase();
@@ -162,6 +151,10 @@ private:
const QVector<Utf8String> &deps{data->deps}; const QVector<Utf8String> &deps{data->deps};
}; };
// NOTE: some tests are disabled because clang code model does not need to follow symbols
// to other translation units. When there's infrastructure to test database based follow symbol
// they should be moved there.
TEST_F(FollowSymbol, CursorOnNamespace) TEST_F(FollowSymbol, CursorOnNamespace)
{ {
const auto namespaceDefinition = followSymbol(27, 1); const auto namespaceDefinition = followSymbol(27, 1);
@@ -183,7 +176,7 @@ TEST_F(FollowSymbol, CursorOnClassForwardDeclarationFollowToHeader)
ASSERT_THAT(classDefinition, MatchesHeaderSourceRange(34, 7, 3)); ASSERT_THAT(classDefinition, MatchesHeaderSourceRange(34, 7, 3));
} }
TEST_F(FollowSymbol, CursorOnClassForwardDeclarationFollowToCpp) TEST_F(FollowSymbol, DISABLED_CursorOnClassForwardDeclarationFollowToCpp)
{ {
const auto classDefinition = followHeaderSymbol(48, 9); const auto classDefinition = followHeaderSymbol(48, 9);
@@ -204,7 +197,7 @@ TEST_F(FollowSymbol, CursorOnClassDefinitionInCpp)
ASSERT_THAT(classForwardDeclaration, MatchesHeaderSourceRange(48, 7, 8)); ASSERT_THAT(classForwardDeclaration, MatchesHeaderSourceRange(48, 7, 8));
} }
TEST_F(FollowSymbol, CursorOnConstructorDeclaration) TEST_F(FollowSymbol, DISABLED_CursorOnConstructorDeclaration)
{ {
const auto constructorDefinition = followHeaderSymbol(36, 5); const auto constructorDefinition = followHeaderSymbol(36, 5);
@@ -239,14 +232,14 @@ TEST_F(FollowSymbol, CursorOnFunctionReference)
ASSERT_THAT(functionDefinition, MatchesSourceRange(35, 5, 3)); ASSERT_THAT(functionDefinition, MatchesSourceRange(35, 5, 3));
} }
TEST_F(FollowSymbol, CursorOnMemberFunctionReference) TEST_F(FollowSymbol, DISABLED_CursorOnMemberFunctionReference)
{ {
const auto memberFunctionDefinition = followSymbol(42, 12); const auto memberFunctionDefinition = followSymbol(42, 12);
ASSERT_THAT(memberFunctionDefinition, MatchesSourceRange(49, 21, 3)); ASSERT_THAT(memberFunctionDefinition, MatchesSourceRange(49, 21, 3));
} }
TEST_F(FollowSymbol, CursorOnFunctionWithoutDefinitionReference) TEST_F(FollowSymbol, DISABLED_CursorOnFunctionWithoutDefinitionReference)
{ {
const auto functionDeclaration = followSymbol(43, 5); const auto functionDeclaration = followSymbol(43, 5);
@@ -267,7 +260,7 @@ TEST_F(FollowSymbol, CursorOnMemberFunctionDefinition)
ASSERT_THAT(memberFunctionDeclaration, MatchesHeaderSourceRange(43, 9, 3)); ASSERT_THAT(memberFunctionDeclaration, MatchesHeaderSourceRange(43, 9, 3));
} }
TEST_F(FollowSymbol, CursorOnMemberFunctionDeclaration) TEST_F(FollowSymbol, DISABLED_CursorOnMemberFunctionDeclaration)
{ {
const auto memberFunctionDefinition = followHeaderSymbol(43, 9); const auto memberFunctionDefinition = followHeaderSymbol(43, 9);
@@ -302,14 +295,14 @@ TEST_F(FollowSymbol, CursorOnStaticVariable)
ASSERT_THAT(staticVariableDeclaration, MatchesHeaderSourceRange(30, 7, 7)); ASSERT_THAT(staticVariableDeclaration, MatchesHeaderSourceRange(30, 7, 7));
} }
TEST_F(FollowSymbol, CursorOnFunctionFromOtherClass) TEST_F(FollowSymbol, DISABLED_CursorOnFunctionFromOtherClass)
{ {
const auto functionDefinition = followSymbol(62, 39); const auto functionDefinition = followSymbol(62, 39);
ASSERT_THAT(functionDefinition, MatchesFileSourceRange(cursorPath, 104, 22, 8)); ASSERT_THAT(functionDefinition, MatchesFileSourceRange(cursorPath, 104, 22, 8));
} }
TEST_F(FollowSymbol, CursorOnDefineReference) TEST_F(FollowSymbol, DISABLED_CursorOnDefineReference)
{ {
const auto functionDefinition = followSymbol(66, 43); const auto functionDefinition = followSymbol(66, 43);

View File

@@ -531,7 +531,6 @@ std::ostream &operator<<(std::ostream &os, const RequestFollowSymbolMessage &mes
{ {
os << "(" os << "("
<< message.fileContainer() << ", " << message.fileContainer() << ", "
<< message.dependentFiles() << ", "
<< message.ticketNumber() << ", " << message.ticketNumber() << ", "
<< message.line() << ", " << message.line() << ", "
<< message.column() << ", " << message.column() << ", "

View File

@@ -205,10 +205,7 @@ TEST_F(ReadAndWriteMessageBlock, CompareRequestReferences)
TEST_F(ReadAndWriteMessageBlock, CompareRequestFollowSymbol) TEST_F(ReadAndWriteMessageBlock, CompareRequestFollowSymbol)
{ {
QVector<Utf8String> dependentFiles; CompareMessage(ClangBackEnd::RequestFollowSymbolMessage{fileContainer, 13, 37});
dependentFiles.push_back(QString("somefile.cpp"));
dependentFiles.push_back(QString("otherfile.cpp"));
CompareMessage(ClangBackEnd::RequestFollowSymbolMessage{fileContainer, dependentFiles, 13, 37});
} }
TEST_F(ReadAndWriteMessageBlock, CompareReferences) TEST_F(ReadAndWriteMessageBlock, CompareReferences)