forked from qt-creator/qt-creator
Clang: Provide highlighting for identifier under cursor
Change-Id: I80ffe23cbcc84ab7323124581d9dd6afbe974fd0 Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -39,6 +39,7 @@ SOURCES += $$PWD/clangcodemodelserverinterface.cpp \
|
||||
$$PWD/sourcelocationcontainer.cpp \
|
||||
$$PWD/fixitcontainer.cpp \
|
||||
$$PWD/requestdocumentannotations.cpp \
|
||||
$$PWD/requestreferencesmessage.cpp \
|
||||
$$PWD/registerunsavedfilesforeditormessage.cpp \
|
||||
$$PWD/unregisterunsavedfilesforeditormessage.cpp \
|
||||
$$PWD/updatetranslationunitsforeditormessage.cpp \
|
||||
@@ -52,6 +53,7 @@ SOURCES += $$PWD/clangcodemodelserverinterface.cpp \
|
||||
$$PWD/ipcserverinterface.cpp \
|
||||
$$PWD/clangcodemodelconnectionclient.cpp \
|
||||
$$PWD/documentannotationschangedmessage.cpp \
|
||||
$$PWD/referencesmessage.cpp \
|
||||
$$PWD/refactoringclientproxy.cpp \
|
||||
$$PWD/sourcelocationscontainer.cpp \
|
||||
$$PWD/sourcelocationcontainerv2.cpp \
|
||||
@@ -112,6 +114,8 @@ HEADERS += \
|
||||
$$PWD/sourcelocationcontainer.h \
|
||||
$$PWD/fixitcontainer.h \
|
||||
$$PWD/requestdocumentannotations.h \
|
||||
$$PWD/referencesmessage.h \
|
||||
$$PWD/requestreferencesmessage.h \
|
||||
$$PWD/registerunsavedfilesforeditormessage.h \
|
||||
$$PWD/unregisterunsavedfilesforeditormessage.h \
|
||||
$$PWD/updatetranslationunitsforeditormessage.h \
|
||||
|
||||
@@ -113,6 +113,9 @@ enum class MessageType : quint8 {
|
||||
RequestDocumentAnnotationsMessage,
|
||||
DocumentAnnotationsChangedMessage,
|
||||
|
||||
RequestReferencesMessage,
|
||||
ReferencesMessage,
|
||||
|
||||
UpdateVisibleTranslationUnitsMessage,
|
||||
|
||||
CompleteCodeMessage,
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "cmbcodecompletedmessage.h"
|
||||
#include "cmbechomessage.h"
|
||||
#include "documentannotationschangedmessage.h"
|
||||
#include "referencesmessage.h"
|
||||
#include "messageenvelop.h"
|
||||
#include "projectpartsdonotexistmessage.h"
|
||||
#include "translationunitdoesnotexistmessage.h"
|
||||
@@ -58,6 +59,9 @@ void ClangCodeModelClientInterface::dispatch(const MessageEnvelop &messageEnvelo
|
||||
case MessageType::DocumentAnnotationsChangedMessage:
|
||||
documentAnnotationsChanged(messageEnvelop.message<DocumentAnnotationsChangedMessage>());
|
||||
break;
|
||||
case MessageType::ReferencesMessage:
|
||||
references(messageEnvelop.message<ReferencesMessage>());
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unknown ClangCodeModelClientMessage";
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ class RegisterUnsavedFilesForEditorMessage;
|
||||
class UnregisterUnsavedFilesForEditorMessage;
|
||||
class UpdateVisibleTranslationUnitsMessage;
|
||||
class RequestDocumentAnnotationsMessage;
|
||||
class RequestReferencesMessage;
|
||||
class ReferencesMessage;
|
||||
class DocumentAnnotationsChangedMessage;
|
||||
|
||||
class CMBIPC_EXPORT ClangCodeModelClientInterface : public IpcClientInterface
|
||||
@@ -57,6 +59,7 @@ public:
|
||||
virtual void translationUnitDoesNotExist(const TranslationUnitDoesNotExistMessage &message) = 0;
|
||||
virtual void projectPartsDoNotExist(const ProjectPartsDoNotExistMessage &message) = 0;
|
||||
virtual void documentAnnotationsChanged(const DocumentAnnotationsChangedMessage &message) = 0;
|
||||
virtual void references(const ReferencesMessage &message) = 0;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "cmbechomessage.h"
|
||||
#include "cmbregistertranslationunitsforeditormessage.h"
|
||||
#include "documentannotationschangedmessage.h"
|
||||
#include "referencesmessage.h"
|
||||
#include "clangcodemodelserverinterface.h"
|
||||
#include "ipcserverinterface.h"
|
||||
#include "messageenvelop.h"
|
||||
@@ -101,6 +102,11 @@ void ClangCodeModelClientProxy::documentAnnotationsChanged(const DocumentAnnotat
|
||||
m_writeMessageBlock.write(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelClientProxy::references(const ReferencesMessage &message)
|
||||
{
|
||||
m_writeMessageBlock.write(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelClientProxy::readMessages()
|
||||
{
|
||||
for (const MessageEnvelop &message : m_readMessageBlock.readAll())
|
||||
|
||||
@@ -57,6 +57,7 @@ public:
|
||||
void translationUnitDoesNotExist(const TranslationUnitDoesNotExistMessage &message) override;
|
||||
void projectPartsDoNotExist(const ProjectPartsDoNotExistMessage &message) override;
|
||||
void documentAnnotationsChanged(const DocumentAnnotationsChangedMessage &message) override;
|
||||
void references(const ReferencesMessage &message) override;
|
||||
|
||||
void readMessages();
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "messageenvelop.h"
|
||||
#include "registerunsavedfilesforeditormessage.h"
|
||||
#include "requestdocumentannotations.h"
|
||||
#include "requestreferencesmessage.h"
|
||||
#include "unregisterunsavedfilesforeditormessage.h"
|
||||
#include "updatetranslationunitsforeditormessage.h"
|
||||
#include "updatevisibletranslationunitsmessage.h"
|
||||
@@ -75,6 +76,9 @@ void ClangCodeModelServerInterface::dispatch(const MessageEnvelop &messageEnvelo
|
||||
case MessageType::RequestDocumentAnnotationsMessage:
|
||||
requestDocumentAnnotations(messageEnvelop.message<RequestDocumentAnnotationsMessage>());
|
||||
break;
|
||||
case MessageType::RequestReferencesMessage:
|
||||
requestReferences(messageEnvelop.message<RequestReferencesMessage>());
|
||||
break;
|
||||
case MessageType::UpdateVisibleTranslationUnitsMessage:
|
||||
updateVisibleTranslationUnits(messageEnvelop.message<UpdateVisibleTranslationUnitsMessage>());
|
||||
break;
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
virtual void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message) = 0;
|
||||
virtual void completeCode(const CompleteCodeMessage &message) = 0;
|
||||
virtual void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) = 0;
|
||||
virtual void requestReferences(const RequestReferencesMessage &message) = 0;
|
||||
virtual void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <messageenvelop.h>
|
||||
#include <registerunsavedfilesforeditormessage.h>
|
||||
#include <requestdocumentannotations.h>
|
||||
#include <requestreferencesmessage.h>
|
||||
#include <unregisterunsavedfilesforeditormessage.h>
|
||||
#include <updatetranslationunitsforeditormessage.h>
|
||||
#include <updatevisibletranslationunitsmessage.h>
|
||||
@@ -116,6 +117,11 @@ void ClangCodeModelServerProxy::requestDocumentAnnotations(const RequestDocument
|
||||
m_writeMessageBlock.write(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServerProxy::requestReferences(const RequestReferencesMessage &message)
|
||||
{
|
||||
m_writeMessageBlock.write(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServerProxy::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
|
||||
{
|
||||
m_writeMessageBlock.write(message);
|
||||
|
||||
@@ -59,6 +59,7 @@ public:
|
||||
void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message) override;
|
||||
void completeCode(const CompleteCodeMessage &message) override;
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const RequestReferencesMessage &message) override;
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
||||
|
||||
void readMessages();
|
||||
|
||||
@@ -33,11 +33,13 @@
|
||||
#include "cmbunregisterprojectsforeditormessage.h"
|
||||
#include "cmbunregistertranslationunitsforeditormessage.h"
|
||||
#include "documentannotationschangedmessage.h"
|
||||
#include "referencesmessage.h"
|
||||
#include "messageenvelop.h"
|
||||
#include "messageenvelop.h"
|
||||
#include "projectpartsdonotexistmessage.h"
|
||||
#include "registerunsavedfilesforeditormessage.h"
|
||||
#include "requestdocumentannotations.h"
|
||||
#include "requestreferencesmessage.h"
|
||||
#include "translationunitdoesnotexistmessage.h"
|
||||
#include "unregisterunsavedfilesforeditormessage.h"
|
||||
#include "updatetranslationunitsforeditormessage.h"
|
||||
@@ -80,6 +82,9 @@ QDebug operator<<(QDebug debug, const MessageEnvelop &messageEnvelop)
|
||||
case MessageType::RequestDocumentAnnotationsMessage:
|
||||
qDebug() << messageEnvelop.message<RequestDocumentAnnotationsMessage>();
|
||||
break;
|
||||
case MessageType::RequestReferencesMessage:
|
||||
qDebug() << messageEnvelop.message<RequestReferencesMessage>();
|
||||
break;
|
||||
case MessageType::UpdateVisibleTranslationUnitsMessage:
|
||||
qDebug() << messageEnvelop.message<UpdateVisibleTranslationUnitsMessage>();
|
||||
break;
|
||||
@@ -92,6 +97,9 @@ QDebug operator<<(QDebug debug, const MessageEnvelop &messageEnvelop)
|
||||
case MessageType::CodeCompletedMessage:
|
||||
qDebug() << messageEnvelop.message<CodeCompletedMessage>();
|
||||
break;
|
||||
case MessageType::ReferencesMessage:
|
||||
qDebug() << messageEnvelop.message<ReferencesMessage>();
|
||||
break;
|
||||
case MessageType::TranslationUnitDoesNotExistMessage:
|
||||
qDebug() << messageEnvelop.message<TranslationUnitDoesNotExistMessage>();
|
||||
break;
|
||||
|
||||
59
src/libs/clangbackendipc/referencesmessage.cpp
Normal file
59
src/libs/clangbackendipc/referencesmessage.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "referencesmessage.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
QDebug operator<<(QDebug debug, const ReferencesMessage &message)
|
||||
{
|
||||
debug.nospace() << "ReferencesMessage("
|
||||
<< message.fileContainer()
|
||||
<< ", " << message.m_ticketNumber
|
||||
<< ", " << message.m_isLocalVariable
|
||||
<< ", " << message.m_references;
|
||||
|
||||
debug.nospace() << ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const ReferencesMessage &message)
|
||||
{
|
||||
os << "("
|
||||
<< message.m_fileContainer << ", "
|
||||
<< message.m_ticketNumber << ", "
|
||||
<< message.m_isLocalVariable << ", "
|
||||
<< message.m_references << ", "
|
||||
<< ")";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
110
src/libs/clangbackendipc/referencesmessage.h
Normal file
110
src/libs/clangbackendipc/referencesmessage.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filecontainer.h"
|
||||
#include "sourcerangecontainer.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <QVector>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class ReferencesMessage
|
||||
{
|
||||
public:
|
||||
ReferencesMessage() = default;
|
||||
ReferencesMessage(const FileContainer &fileContainer,
|
||||
const QVector<SourceRangeContainer> &references,
|
||||
bool isLocalVariable,
|
||||
quint64 ticketNumber)
|
||||
: m_fileContainer(fileContainer)
|
||||
, m_references(references)
|
||||
, m_ticketNumber(ticketNumber)
|
||||
, m_isLocalVariable(isLocalVariable)
|
||||
{
|
||||
}
|
||||
|
||||
const FileContainer &fileContainer() const
|
||||
{
|
||||
return m_fileContainer;
|
||||
}
|
||||
|
||||
bool isLocalVariable() const
|
||||
{
|
||||
return m_isLocalVariable;
|
||||
}
|
||||
|
||||
const QVector<SourceRangeContainer> &references() const
|
||||
{
|
||||
return m_references;
|
||||
}
|
||||
|
||||
quint64 ticketNumber() const
|
||||
{
|
||||
return m_ticketNumber;
|
||||
}
|
||||
|
||||
friend QDataStream &operator<<(QDataStream &out, const ReferencesMessage &message)
|
||||
{
|
||||
out << message.m_fileContainer;
|
||||
out << message.m_isLocalVariable;
|
||||
out << message.m_references;
|
||||
out << message.m_ticketNumber;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
friend QDataStream &operator>>(QDataStream &in, ReferencesMessage &message)
|
||||
{
|
||||
in >> message.m_fileContainer;
|
||||
in >> message.m_isLocalVariable;
|
||||
in >> message.m_references;
|
||||
in >> message.m_ticketNumber;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
friend bool operator==(const ReferencesMessage &first, const ReferencesMessage &second)
|
||||
{
|
||||
return first.m_ticketNumber == second.m_ticketNumber
|
||||
&& first.m_isLocalVariable == second.m_isLocalVariable
|
||||
&& first.m_fileContainer == second.m_fileContainer
|
||||
&& first.m_references == second.m_references;
|
||||
}
|
||||
|
||||
friend CMBIPC_EXPORT QDebug operator<<(QDebug debug, const ReferencesMessage &message);
|
||||
friend std::ostream &operator<<(std::ostream &os, const ReferencesMessage &message);
|
||||
|
||||
private:
|
||||
FileContainer m_fileContainer;
|
||||
QVector<SourceRangeContainer> m_references;
|
||||
quint64 m_ticketNumber = 0;
|
||||
bool m_isLocalVariable = false;
|
||||
};
|
||||
|
||||
DECLARE_MESSAGE(ReferencesMessage)
|
||||
} // namespace ClangBackEnd
|
||||
62
src/libs/clangbackendipc/requestreferencesmessage.cpp
Normal file
62
src/libs/clangbackendipc/requestreferencesmessage.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "requestreferencesmessage.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
quint64 RequestReferencesMessage::ticketCounter = 0;
|
||||
|
||||
QDebug operator<<(QDebug debug, const RequestReferencesMessage &message)
|
||||
{
|
||||
debug.nospace() << "RequestReferencesMessage(";
|
||||
|
||||
debug.nospace() << message.m_fileContainer << ", ";
|
||||
debug.nospace() << message.m_ticketNumber << ", ";
|
||||
debug.nospace() << message.m_line << ", ";
|
||||
debug.nospace() << message.m_column << ", ";
|
||||
|
||||
debug.nospace() << ")";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const RequestReferencesMessage &message)
|
||||
{
|
||||
os << "("
|
||||
<< message.m_fileContainer << ", "
|
||||
<< message.m_ticketNumber << ", "
|
||||
<< message.m_line << ", "
|
||||
<< message.m_column << ", "
|
||||
<< ")";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
111
src/libs/clangbackendipc/requestreferencesmessage.h
Normal file
111
src/libs/clangbackendipc/requestreferencesmessage.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "clangbackendipc_global.h"
|
||||
|
||||
#include "filecontainer.h"
|
||||
|
||||
#include <QDataStream>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class RequestReferencesMessage
|
||||
{
|
||||
public:
|
||||
RequestReferencesMessage() = default;
|
||||
RequestReferencesMessage(const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column)
|
||||
: m_fileContainer(fileContainer)
|
||||
, m_ticketNumber(++ticketCounter)
|
||||
, m_line(line)
|
||||
, m_column(column)
|
||||
{
|
||||
}
|
||||
|
||||
const FileContainer fileContainer() const
|
||||
{
|
||||
return m_fileContainer;
|
||||
}
|
||||
|
||||
quint32 line() const
|
||||
{
|
||||
return m_line;
|
||||
}
|
||||
|
||||
quint32 column() const
|
||||
{
|
||||
return m_column;
|
||||
}
|
||||
|
||||
quint64 ticketNumber() const
|
||||
{
|
||||
return m_ticketNumber;
|
||||
}
|
||||
|
||||
friend QDataStream &operator<<(QDataStream &out, const RequestReferencesMessage &message)
|
||||
{
|
||||
out << message.m_fileContainer;
|
||||
out << message.m_ticketNumber;
|
||||
out << message.m_line;
|
||||
out << message.m_column;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
friend QDataStream &operator>>(QDataStream &in, RequestReferencesMessage &message)
|
||||
{
|
||||
in >> message.m_fileContainer;
|
||||
in >> message.m_ticketNumber;
|
||||
in >> message.m_line;
|
||||
in >> message.m_column;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
friend bool operator==(const RequestReferencesMessage &first,
|
||||
const RequestReferencesMessage &second)
|
||||
{
|
||||
return first.m_ticketNumber == second.m_ticketNumber
|
||||
&& first.m_line == second.m_line
|
||||
&& first.m_column == second.m_column
|
||||
&& first.m_fileContainer == second.m_fileContainer;
|
||||
}
|
||||
|
||||
friend CMBIPC_EXPORT QDebug operator<<(QDebug debug, const RequestReferencesMessage &message);
|
||||
friend std::ostream &operator<<(std::ostream &os, const RequestReferencesMessage &message);
|
||||
|
||||
private:
|
||||
FileContainer m_fileContainer;
|
||||
quint64 m_ticketNumber = 0;
|
||||
quint32 m_line = 0;
|
||||
quint32 m_column = 0;
|
||||
static CMBIPC_EXPORT quint64 ticketCounter;
|
||||
};
|
||||
|
||||
DECLARE_MESSAGE(RequestReferencesMessage);
|
||||
} // namespace ClangBackEnd
|
||||
@@ -58,8 +58,11 @@
|
||||
#include <clangbackendipc/cmbunregistertranslationunitsforeditormessage.h>
|
||||
#include <clangbackendipc/cmbunregisterprojectsforeditormessage.h>
|
||||
#include <clangbackendipc/documentannotationschangedmessage.h>
|
||||
#include <clangbackendipc/referencesmessage.h>
|
||||
#include <clangbackendipc/requestreferencesmessage.h>
|
||||
#include <clangbackendipc/registerunsavedfilesforeditormessage.h>
|
||||
#include <clangbackendipc/requestdocumentannotations.h>
|
||||
#include <clangbackendipc/requestreferencesmessage.h>
|
||||
#include <clangbackendipc/filecontainer.h>
|
||||
#include <clangbackendipc/projectpartsdonotexistmessage.h>
|
||||
#include <clangbackendipc/translationunitdoesnotexistmessage.h>
|
||||
@@ -74,6 +77,7 @@
|
||||
#include <QElapsedTimer>
|
||||
#include <QLoggingCategory>
|
||||
#include <QProcess>
|
||||
#include <QTextBlock>
|
||||
|
||||
static Q_LOGGING_CATEGORY(log, "qtc.clangcodemodel.ipc")
|
||||
|
||||
@@ -150,6 +154,21 @@ void IpcReceiver::deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *t
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<CppTools::CursorInfo> IpcReceiver::addExpectedReferencesMessage(quint64 ticket,
|
||||
QTextDocument *textDocument)
|
||||
{
|
||||
QTC_CHECK(textDocument);
|
||||
QTC_CHECK(!m_referencesTable.contains(ticket));
|
||||
|
||||
QFutureInterface<CppTools::CursorInfo> futureInterface;
|
||||
futureInterface.reportStarted();
|
||||
|
||||
const ReferencesEntry entry{futureInterface, textDocument};
|
||||
m_referencesTable.insert(ticket, entry);
|
||||
|
||||
return futureInterface.future();
|
||||
}
|
||||
|
||||
bool IpcReceiver::isExpectingCodeCompletedMessage() const
|
||||
{
|
||||
return !m_assistProcessorsTable.isEmpty();
|
||||
@@ -205,6 +224,56 @@ void IpcReceiver::documentAnnotationsChanged(const DocumentAnnotationsChangedMes
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
CppTools::CursorInfo::Range toCursorInfoRange(const QTextDocument &textDocument,
|
||||
const SourceRangeContainer &sourceRange)
|
||||
{
|
||||
const SourceLocationContainer start = sourceRange.start();
|
||||
const SourceLocationContainer end = sourceRange.end();
|
||||
const unsigned length = end.column() - start.column();
|
||||
|
||||
const QTextBlock block = textDocument.findBlockByNumber(static_cast<int>(start.line()) - 1);
|
||||
const int shift = ClangCodeModel::Utils::extraUtf8CharsShift(block.text(),
|
||||
static_cast<int>(start.column()));
|
||||
const uint column = start.column() - static_cast<uint>(shift);
|
||||
|
||||
return CppTools::CursorInfo::Range(start.line(), column, length);
|
||||
}
|
||||
|
||||
static
|
||||
CppTools::CursorInfo toCursorInfo(const QTextDocument &textDocument,
|
||||
const ReferencesMessage &message)
|
||||
{
|
||||
CppTools::CursorInfo result;
|
||||
const QVector<SourceRangeContainer> references = message.references();
|
||||
|
||||
result.areUseRangesForLocalVariable = message.isLocalVariable();
|
||||
for (const SourceRangeContainer &reference : references)
|
||||
result.useRanges.append(toCursorInfoRange(textDocument, reference));
|
||||
|
||||
result.useRanges.reserve(references.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void IpcReceiver::references(const ReferencesMessage &message)
|
||||
{
|
||||
qCDebug(log) << "<<< ReferencesMessage with"
|
||||
<< message.references().size() << "references";
|
||||
|
||||
const quint64 ticket = message.ticketNumber();
|
||||
const ReferencesEntry entry = m_referencesTable.take(ticket);
|
||||
QFutureInterface<CppTools::CursorInfo> futureInterface = entry.futureInterface;
|
||||
QTC_CHECK(futureInterface != QFutureInterface<CppTools::CursorInfo>());
|
||||
|
||||
if (futureInterface.isCanceled())
|
||||
return; // A new request was issued making this one outdated.
|
||||
|
||||
QTC_CHECK(entry.textDocument);
|
||||
futureInterface.reportResult(toCursorInfo(*entry.textDocument, message));
|
||||
futureInterface.reportFinished();
|
||||
}
|
||||
|
||||
class IpcSender : public IpcSenderInterface
|
||||
{
|
||||
public:
|
||||
@@ -222,6 +291,7 @@ public:
|
||||
void unregisterUnsavedFilesForEditor(const ClangBackEnd::UnregisterUnsavedFilesForEditorMessage &message) override;
|
||||
void completeCode(const ClangBackEnd::CompleteCodeMessage &message) override;
|
||||
void requestDocumentAnnotations(const ClangBackEnd::RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const ClangBackEnd::RequestReferencesMessage &message) override;
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
||||
|
||||
private:
|
||||
@@ -298,6 +368,13 @@ void IpcSender::requestDocumentAnnotations(const RequestDocumentAnnotationsMessa
|
||||
m_connection.serverProxy().requestDocumentAnnotations(message);
|
||||
}
|
||||
|
||||
void IpcSender::requestReferences(const RequestReferencesMessage &message)
|
||||
{
|
||||
QTC_CHECK(m_connection.isConnected());
|
||||
qCDebug(log) << ">>>" << message;
|
||||
m_connection.serverProxy().requestReferences(message);
|
||||
}
|
||||
|
||||
void IpcSender::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
|
||||
{
|
||||
QTC_CHECK(m_connection.isConnected());
|
||||
@@ -318,6 +395,7 @@ public:
|
||||
void unregisterUnsavedFilesForEditor(const ClangBackEnd::UnregisterUnsavedFilesForEditorMessage &) override {}
|
||||
void completeCode(const ClangBackEnd::CompleteCodeMessage &) override {}
|
||||
void requestDocumentAnnotations(const ClangBackEnd::RequestDocumentAnnotationsMessage &) override {}
|
||||
void requestReferences(const ClangBackEnd::RequestReferencesMessage &) override {}
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &) override {}
|
||||
};
|
||||
|
||||
@@ -603,6 +681,18 @@ void IpcCommunicator::requestDocumentAnnotations(const FileContainer &fileContai
|
||||
m_ipcSender->requestDocumentAnnotations(message);
|
||||
}
|
||||
|
||||
QFuture<CppTools::CursorInfo> IpcCommunicator::requestReferences(
|
||||
const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column,
|
||||
QTextDocument *textDocument)
|
||||
{
|
||||
const RequestReferencesMessage message(fileContainer, line, column);
|
||||
m_ipcSender->requestReferences(message);
|
||||
|
||||
return m_ipcReceiver.addExpectedReferencesMessage(message.ticketNumber(), textDocument);
|
||||
}
|
||||
|
||||
void IpcCommunicator::updateTranslationUnitWithRevisionCheck(Core::IDocument *document)
|
||||
{
|
||||
const auto textDocument = qobject_cast<TextDocument*>(document);
|
||||
|
||||
@@ -32,8 +32,10 @@
|
||||
#include <clangbackendipc/clangcodemodelclientinterface.h>
|
||||
#include <clangbackendipc/projectpartcontainer.h>
|
||||
|
||||
#include <QFuture>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QTextDocument>
|
||||
#include <QVector>
|
||||
|
||||
#include <functional>
|
||||
@@ -43,6 +45,10 @@ class IEditor;
|
||||
class IDocument;
|
||||
}
|
||||
|
||||
namespace CppTools {
|
||||
class CursorInfo;
|
||||
}
|
||||
|
||||
namespace ClangBackEnd {
|
||||
class DocumentAnnotationsChangedMessage;
|
||||
}
|
||||
@@ -72,6 +78,9 @@ public:
|
||||
void deleteAndClearWaitingAssistProcessors();
|
||||
void deleteProcessorsOfEditorWidget(TextEditor::TextEditorWidget *textEditorWidget);
|
||||
|
||||
QFuture<CppTools::CursorInfo> addExpectedReferencesMessage(quint64 ticket,
|
||||
QTextDocument *textDocument);
|
||||
|
||||
bool isExpectingCodeCompletedMessage() const;
|
||||
|
||||
private:
|
||||
@@ -80,6 +89,7 @@ private:
|
||||
void codeCompleted(const ClangBackEnd::CodeCompletedMessage &message) override;
|
||||
|
||||
void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &message) override;
|
||||
void references(const ClangBackEnd::ReferencesMessage &message) override;
|
||||
|
||||
void translationUnitDoesNotExist(const ClangBackEnd::TranslationUnitDoesNotExistMessage &) override {}
|
||||
void projectPartsDoNotExist(const ClangBackEnd::ProjectPartsDoNotExistMessage &) override {}
|
||||
@@ -87,6 +97,12 @@ private:
|
||||
private:
|
||||
AliveHandler m_aliveHandler;
|
||||
QHash<quint64, ClangCompletionAssistProcessor *> m_assistProcessorsTable;
|
||||
|
||||
struct ReferencesEntry {
|
||||
QFutureInterface<CppTools::CursorInfo> futureInterface;
|
||||
QTextDocument *textDocument = nullptr;
|
||||
};
|
||||
QHash<quint64, ReferencesEntry> m_referencesTable;
|
||||
const bool m_printAliveMessage = false;
|
||||
};
|
||||
|
||||
@@ -105,6 +121,7 @@ public:
|
||||
virtual void unregisterUnsavedFilesForEditor(const ClangBackEnd::UnregisterUnsavedFilesForEditorMessage &message) = 0;
|
||||
virtual void completeCode(const ClangBackEnd::CompleteCodeMessage &message) = 0;
|
||||
virtual void requestDocumentAnnotations(const ClangBackEnd::RequestDocumentAnnotationsMessage &message) = 0;
|
||||
virtual void requestReferences(const ClangBackEnd::RequestReferencesMessage &message) = 0;
|
||||
virtual void updateVisibleTranslationUnits(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message) = 0;
|
||||
};
|
||||
|
||||
@@ -114,6 +131,7 @@ class IpcCommunicator : public QObject
|
||||
|
||||
public:
|
||||
using Ptr = QSharedPointer<IpcCommunicator>;
|
||||
using FileContainer = ClangBackEnd::FileContainer;
|
||||
using FileContainers = QVector<ClangBackEnd::FileContainer>;
|
||||
using ProjectPartContainers = QVector<ClangBackEnd::ProjectPartContainer>;
|
||||
|
||||
@@ -129,6 +147,9 @@ public:
|
||||
void registerUnsavedFilesForEditor(const FileContainers &fileContainers);
|
||||
void unregisterUnsavedFilesForEditor(const FileContainers &fileContainers);
|
||||
void requestDocumentAnnotations(const ClangBackEnd::FileContainer &fileContainer);
|
||||
QFuture<CppTools::CursorInfo> requestReferences(const FileContainer &fileContainer,
|
||||
quint32 line,
|
||||
quint32 column, QTextDocument *textDocument);
|
||||
void completeCode(ClangCompletionAssistProcessor *assistProcessor, const QString &filePath,
|
||||
quint32 line,
|
||||
quint32 column,
|
||||
|
||||
@@ -68,6 +68,7 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
|
||||
IpcCommunicator &ipcCommunicator,
|
||||
TextEditor::TextDocument *document)
|
||||
: BaseEditorDocumentProcessor(document->document(), document->filePath().toString())
|
||||
, m_document(*document)
|
||||
, m_diagnosticManager(document)
|
||||
, m_ipcCommunicator(ipcCommunicator)
|
||||
, m_parser(new ClangEditorDocumentParser(document->filePath().toString()))
|
||||
@@ -287,10 +288,48 @@ void ClangEditorDocumentProcessor::setParserConfig(
|
||||
m_builtinProcessor.parser()->setConfiguration(config);
|
||||
}
|
||||
|
||||
static bool isCursorOnIdentifier(const QTextCursor &textCursor)
|
||||
{
|
||||
QTextDocument *document = textCursor.document();
|
||||
return CppTools::isValidIdentifierChar(document->characterAt(textCursor.position()));
|
||||
}
|
||||
|
||||
static QFuture<CppTools::CursorInfo> defaultCursorInfoFuture()
|
||||
{
|
||||
QFutureInterface<CppTools::CursorInfo> futureInterface;
|
||||
futureInterface.reportResult(CppTools::CursorInfo());
|
||||
futureInterface.reportFinished();
|
||||
|
||||
return futureInterface.future();
|
||||
}
|
||||
|
||||
static bool convertPosition(const QTextCursor &textCursor, int *line, int *column)
|
||||
{
|
||||
const bool converted = TextEditor::Convenience::convertPosition(textCursor.document(),
|
||||
textCursor.position(),
|
||||
line,
|
||||
column);
|
||||
QTC_CHECK(converted);
|
||||
return converted;
|
||||
}
|
||||
|
||||
QFuture<CppTools::CursorInfo>
|
||||
ClangEditorDocumentProcessor::cursorInfo(const CppTools::CursorInfoParams ¶ms)
|
||||
{
|
||||
return m_builtinProcessor.cursorInfo(params);
|
||||
int line, column;
|
||||
convertPosition(params.textCursor, &line, &column);
|
||||
++column; // for 1-based columns
|
||||
|
||||
if (!isCursorOnIdentifier(params.textCursor))
|
||||
return defaultCursorInfoFuture();
|
||||
|
||||
const QTextBlock block = params.textCursor.document()->findBlockByNumber(line - 1);
|
||||
column += ClangCodeModel::Utils::extraUtf8CharsShift(block.text(), column);
|
||||
|
||||
return m_ipcCommunicator.requestReferences(simpleFileContainer(),
|
||||
static_cast<quint32>(line),
|
||||
static_cast<quint32>(column),
|
||||
textDocument());
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const
|
||||
@@ -396,6 +435,15 @@ ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget(
|
||||
};
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::simpleFileContainer() const
|
||||
{
|
||||
Utf8String projectPartId;
|
||||
if (m_projectPart)
|
||||
projectPartId = m_projectPart->id();
|
||||
|
||||
return ClangBackEnd::FileContainer(filePath(), projectPartId, Utf8String(), false, revision());
|
||||
}
|
||||
|
||||
static CppTools::ProjectPart projectPartForLanguageOption(CppTools::ProjectPart *projectPart)
|
||||
{
|
||||
if (projectPart)
|
||||
|
||||
@@ -101,12 +101,14 @@ private:
|
||||
void requestDocumentAnnotations(const QString &projectpartId);
|
||||
HeaderErrorDiagnosticWidgetCreator creatorForHeaderErrorDiagnosticWidget(
|
||||
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic);
|
||||
ClangBackEnd::FileContainer simpleFileContainer() const;
|
||||
ClangBackEnd::FileContainer fileContainerWithArguments(CppTools::ProjectPart *projectPart) const;
|
||||
ClangBackEnd::FileContainer fileContainerWithArgumentsAndDocumentContent(
|
||||
CppTools::ProjectPart *projectPart) const;
|
||||
ClangBackEnd::FileContainer fileContainerWithDocumentContent(const QString &projectpartId) const;
|
||||
|
||||
private:
|
||||
TextEditor::TextDocument &m_document;
|
||||
ClangDiagnosticManager m_diagnosticManager;
|
||||
IpcCommunicator &m_ipcCommunicator;
|
||||
QSharedPointer<ClangEditorDocumentParser> m_parser;
|
||||
|
||||
@@ -325,6 +325,10 @@ QString toString(const RequestDocumentAnnotationsMessage &)
|
||||
return QStringLiteral("RequestDocumentAnnotationsMessage\n");
|
||||
}
|
||||
|
||||
QString toString(const RequestReferencesMessage &)
|
||||
{
|
||||
return QStringLiteral("RequestReferencesMessage\n");
|
||||
}
|
||||
|
||||
QString toString(const UpdateVisibleTranslationUnitsMessage &)
|
||||
{
|
||||
@@ -364,6 +368,9 @@ public:
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override
|
||||
{ senderLog.append(toString(message)); }
|
||||
|
||||
void requestReferences(const RequestReferencesMessage &message) override
|
||||
{ senderLog.append(toString(message)); }
|
||||
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override
|
||||
{ senderLog.append(toString(message)); }
|
||||
|
||||
|
||||
@@ -105,7 +105,11 @@ void CppUseSelectionsUpdater::update(CallType callType)
|
||||
m_runnerWatcher->setFuture(cppEditorDocument->cursorInfo(params));
|
||||
} else { // synchronous case
|
||||
QFuture<CursorInfo> future = cppEditorDocument->cursorInfo(params);
|
||||
future.waitForFinished();
|
||||
|
||||
// QFuture::waitForFinished seems to block completely, not even
|
||||
// allowing to process events from QLocalSocket.
|
||||
while (!future.isFinished())
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
processResults(future.result());
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ HEADERS += $$PWD/clangcodemodelserver.h \
|
||||
$$PWD/clangsupportivetranslationunitinitializer.h \
|
||||
$$PWD/clangparsesupportivetranslationunitjob.h \
|
||||
$$PWD/clangreparsesupportivetranslationunitjob.h \
|
||||
$$PWD/clangrequestreferencesjob.h \
|
||||
$$PWD/clangreferencescollector.h
|
||||
|
||||
SOURCES += $$PWD/clangcodemodelserver.cpp \
|
||||
$$PWD/codecompleter.cpp \
|
||||
@@ -95,3 +97,5 @@ SOURCES += $$PWD/clangcodemodelserver.cpp \
|
||||
$$PWD/clangsupportivetranslationunitinitializer.cpp \
|
||||
$$PWD/clangparsesupportivetranslationunitjob.cpp \
|
||||
$$PWD/clangreparsesupportivetranslationunitjob.cpp \
|
||||
$$PWD/clangrequestreferencesjob.cpp \
|
||||
$$PWD/clangreferencescollector.cpp
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <documentannotationschangedmessage.h>
|
||||
#include <registerunsavedfilesforeditormessage.h>
|
||||
#include <requestdocumentannotations.h>
|
||||
#include <requestreferencesmessage.h>
|
||||
#include <projectpartsdonotexistmessage.h>
|
||||
#include <translationunitdoesnotexistmessage.h>
|
||||
#include <unregisterunsavedfilesforeditormessage.h>
|
||||
@@ -246,6 +247,31 @@ void ClangCodeModelServer::requestDocumentAnnotations(const RequestDocumentAnnot
|
||||
}
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::requestReferences(const RequestReferencesMessage &message)
|
||||
{
|
||||
TIME_SCOPE_DURATION("ClangCodeModelServer::requestReferences");
|
||||
qWarning() << "ClangCodeModelServer::requestReferences";
|
||||
|
||||
try {
|
||||
const Document document = documents.document(message.fileContainer().filePath(),
|
||||
message.fileContainer().projectPartId());
|
||||
DocumentProcessor processor = documentProcessors().processor(document);
|
||||
|
||||
JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestReferences);
|
||||
jobRequest.line = message.line();
|
||||
jobRequest.column = message.column();
|
||||
jobRequest.ticketNumber = message.ticketNumber();
|
||||
// The unsaved files might get updater later, so take the current
|
||||
// revision for the request.
|
||||
jobRequest.documentRevision = message.fileContainer().documentRevision();
|
||||
|
||||
processor.addJob(jobRequest);
|
||||
processor.process();
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in ClangCodeModelServer::requestReferences:" << exception.what();
|
||||
}
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
|
||||
{
|
||||
TIME_SCOPE_DURATION("ClangCodeModelServer::updateVisibleTranslationUnits");
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
void completeCode(const CompleteCodeMessage &message) override;
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const RequestReferencesMessage &message) override;
|
||||
|
||||
public: // for tests
|
||||
const Documents &documentsForTestOnly() const;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "clangdocument.h"
|
||||
#include "clangtranslationunits.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
@@ -121,6 +122,11 @@ bool DocumentProcessor::isSupportiveTranslationUnitInitialized() const
|
||||
== SupportiveTranslationUnitInitializer::State::Initialized;
|
||||
}
|
||||
|
||||
JobRequests &DocumentProcessor::queue()
|
||||
{
|
||||
return d->jobs.queue();
|
||||
}
|
||||
|
||||
QList<Jobs::RunningJob> DocumentProcessor::runningJobs() const
|
||||
{
|
||||
return d->jobs.runningJobs();
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
|
||||
public: // for tests
|
||||
bool isSupportiveTranslationUnitInitialized() const;
|
||||
JobRequests &queue();
|
||||
QList<Jobs::RunningJob> runningJobs() const;
|
||||
int queueSize() const;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "clangparsesupportivetranslationunitjob.h"
|
||||
#include "clangreparsesupportivetranslationunitjob.h"
|
||||
#include "clangrequestdocumentannotationsjob.h"
|
||||
#include "clangrequestreferencesjob.h"
|
||||
#include "clangupdatedocumentannotationsjob.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(jobsLog, "qtc.clangbackend.jobs");
|
||||
@@ -51,6 +52,8 @@ IAsyncJob *IAsyncJob::create(JobRequest::Type type)
|
||||
return new CompleteCodeJob();
|
||||
case JobRequest::Type::RequestDocumentAnnotations:
|
||||
return new RequestDocumentAnnotationsJob();
|
||||
case JobRequest::Type::RequestReferences:
|
||||
return new RequestReferencesJob();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
@@ -197,6 +197,20 @@ JobRequests JobQueue::takeJobRequestsToRunNow()
|
||||
if (isJobRunningForTranslationUnit(id))
|
||||
continue;
|
||||
|
||||
if (request.conditions.testFlag(JobRequest::Condition::CurrentDocumentRevision)) {
|
||||
if (document.isDirty()) {
|
||||
// TODO: If the document is dirty due to a project update,
|
||||
// references are processes later than ideal.
|
||||
qWarning() << "Not choosing due to dirty document:" << request;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (request.documentRevision != document.documentRevision()) {
|
||||
qWarning() << "Not choosing due to revision mismatch:" << request;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
translationUnitsScheduledForThisRun.insert(id);
|
||||
jobsToRun += request;
|
||||
i.remove();
|
||||
@@ -237,7 +251,7 @@ void JobQueue::setIsJobRunningForJobRequestHandler(
|
||||
m_isJobRunningForJobRequestHandler = isJobRunningHandler;
|
||||
}
|
||||
|
||||
JobRequests JobQueue::queue() const
|
||||
JobRequests &JobQueue::queue()
|
||||
{
|
||||
return m_queue;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
const IsJobRunningForJobRequestHandler &isJobRunningHandler);
|
||||
|
||||
public: // for tests
|
||||
JobRequests queue() const;
|
||||
JobRequests &queue();
|
||||
int size() const;
|
||||
void prioritizeRequests();
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ static const char *JobRequestTypeToText(JobRequest::Type type)
|
||||
RETURN_TEXT_FOR_CASE(CreateInitialDocumentPreamble);
|
||||
RETURN_TEXT_FOR_CASE(CompleteCode);
|
||||
RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations);
|
||||
RETURN_TEXT_FOR_CASE(RequestReferences);
|
||||
}
|
||||
|
||||
return "UnhandledJobRequestType";
|
||||
@@ -90,6 +91,7 @@ bool JobRequest::operator==(const JobRequest &other) const
|
||||
{
|
||||
return type == other.type
|
||||
&& expirationReasons == other.expirationReasons
|
||||
&& conditions == other.conditions
|
||||
|
||||
&& filePath == other.filePath
|
||||
&& projectPartId == other.projectPartId
|
||||
@@ -108,6 +110,7 @@ JobRequest::ExpirationReasons JobRequest::expirationReasonsForType(Type type)
|
||||
switch (type) {
|
||||
case JobRequest::Type::UpdateDocumentAnnotations:
|
||||
return JobRequest::ExpirationReasons(JobRequest::AnythingChanged);
|
||||
case JobRequest::Type::RequestReferences:
|
||||
case JobRequest::Type::RequestDocumentAnnotations:
|
||||
return JobRequest::ExpirationReasons(JobRequest::DocumentClosed
|
||||
|JobRequest::DocumentRevisionChanged);
|
||||
@@ -121,4 +124,12 @@ JobRequest::ExpirationReasons JobRequest::expirationReasonsForType(Type type)
|
||||
return JobRequest::ExpirationReasons(JobRequest::DocumentClosed);
|
||||
}
|
||||
|
||||
JobRequest::Conditions JobRequest::conditionsForType(JobRequest::Type type)
|
||||
{
|
||||
if (type == JobRequest::Type::RequestReferences)
|
||||
return JobRequest::Conditions(JobRequest::Condition::CurrentDocumentRevision);
|
||||
|
||||
return JobRequest::Conditions(JobRequest::Condition::NoCondition);
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -52,8 +52,15 @@ public:
|
||||
|
||||
CompleteCode,
|
||||
RequestDocumentAnnotations,
|
||||
RequestReferences,
|
||||
};
|
||||
|
||||
enum class Condition {
|
||||
NoCondition,
|
||||
CurrentDocumentRevision,
|
||||
};
|
||||
Q_DECLARE_FLAGS(Conditions, Condition)
|
||||
|
||||
enum ExpirationReason {
|
||||
Never = 1 << 0,
|
||||
|
||||
@@ -71,6 +78,7 @@ public:
|
||||
|
||||
public:
|
||||
static ExpirationReasons expirationReasonsForType(Type type);
|
||||
static Conditions conditionsForType(Type type);
|
||||
|
||||
JobRequest();
|
||||
|
||||
@@ -80,6 +88,7 @@ public:
|
||||
quint64 id = 0;
|
||||
Type type;
|
||||
ExpirationReasons expirationReasons;
|
||||
Conditions conditions;
|
||||
|
||||
// General
|
||||
Utf8String filePath;
|
||||
@@ -89,7 +98,7 @@ public:
|
||||
uint documentRevision = 0;
|
||||
PreferredTranslationUnit preferredTranslationUnit = PreferredTranslationUnit::RecentlyParsed;
|
||||
|
||||
// For code completion
|
||||
// Specific to some jobs
|
||||
quint32 line = 0;
|
||||
quint32 column = 0;
|
||||
quint64 ticketNumber = 0;
|
||||
|
||||
@@ -76,6 +76,7 @@ JobRequest Jobs::createJobRequest(const Document &document,
|
||||
JobRequest jobRequest;
|
||||
jobRequest.type = type;
|
||||
jobRequest.expirationReasons = JobRequest::expirationReasonsForType(type);
|
||||
jobRequest.conditions = JobRequest::conditionsForType(type);
|
||||
jobRequest.filePath = document.filePath();
|
||||
jobRequest.projectPartId = document.projectPart().id();
|
||||
jobRequest.unsavedFilesChangeTimePoint = m_unsavedFiles.lastChangeTimePoint();
|
||||
@@ -173,7 +174,7 @@ QList<Jobs::RunningJob> Jobs::runningJobs() const
|
||||
return m_running.values();
|
||||
}
|
||||
|
||||
JobRequests Jobs::queue() const
|
||||
JobRequests &Jobs::queue()
|
||||
{
|
||||
return m_queue.queue();
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
|
||||
public /*for tests*/:
|
||||
QList<RunningJob> runningJobs() const;
|
||||
JobRequests queue() const;
|
||||
JobRequests &queue();
|
||||
bool isJobRunningForTranslationUnit(const Utf8String &translationUnitId) const;
|
||||
bool isJobRunningForJobRequest(const JobRequest &jobRequest) const;
|
||||
|
||||
|
||||
253
src/tools/clangbackend/ipcsource/clangreferencescollector.cpp
Normal file
253
src/tools/clangbackend/ipcsource/clangreferencescollector.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangreferencescollector.h"
|
||||
|
||||
#include "clangstring.h"
|
||||
#include "cursor.h"
|
||||
#include "sourcerange.h"
|
||||
|
||||
#include <clangbackendipc/sourcerangecontainer.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <utf8string.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
namespace {
|
||||
|
||||
class ReferencedCursor
|
||||
{
|
||||
public:
|
||||
static ReferencedCursor find(const Cursor &cursor)
|
||||
{
|
||||
// Query the referenced cursor directly instead of first testing with cursor.isReference().
|
||||
// cursor.isReference() reports false for e.g. CXCursor_DeclRefExpr or CXCursor_CallExpr
|
||||
// although it returns a valid cursor.
|
||||
const Cursor referenced = cursor.referenced();
|
||||
if (referenced.isValid())
|
||||
return handleReferenced(referenced);
|
||||
|
||||
const Cursor definition = cursor.definition();
|
||||
if (definition.isValid())
|
||||
return definition;
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
Utf8String usr() const
|
||||
{
|
||||
return cursor.unifiedSymbolResolution() + usrSuffix;
|
||||
}
|
||||
|
||||
bool isLocalVariable() const
|
||||
{
|
||||
return cursor.isLocalVariable();
|
||||
}
|
||||
|
||||
private:
|
||||
ReferencedCursor(const Cursor &cursor, const Utf8String &usrSuffix = Utf8String())
|
||||
: cursor(cursor)
|
||||
, usrSuffix(usrSuffix)
|
||||
{}
|
||||
|
||||
static ReferencedCursor handleReferenced(const Cursor &cursor)
|
||||
{
|
||||
if (cursor.kind() == CXCursor_OverloadedDeclRef) {
|
||||
// e.g. Text cursor is on "App" of "using N::App;".
|
||||
if (cursor.overloadedDeclarationsCount() >= 1)
|
||||
return cursor.overloadedDeclaration(0);
|
||||
}
|
||||
|
||||
if (cursor.isConstructorOrDestructor()) {
|
||||
const Type type = cursor.type();
|
||||
if (type.isValid()) {
|
||||
const Cursor typeDeclaration = type.declaration();
|
||||
if (typeDeclaration.isValid()) {
|
||||
// A CXCursor_CallExpr like "new Foo" has a type of CXType_Record and its
|
||||
// declaration is e.g. CXCursor_ClassDecl.
|
||||
return typeDeclaration;
|
||||
} else {
|
||||
// A CXCursor_Constructor like "Foo();" has a type of CXType_FunctionProto
|
||||
// and its type declaration is invalid, so use the semantic parent.
|
||||
const Cursor parent = cursor.semanticParent();
|
||||
if (parent.isValid())
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cursor.isFunctionLike() || cursor.isTemplateLike()) {
|
||||
const Cursor parent = cursor.semanticParent();
|
||||
const ClangString spelling = cursor.spelling();
|
||||
return {parent, Utf8StringLiteral("_qtc_") + Utf8String(spelling)};
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
private:
|
||||
Cursor cursor;
|
||||
Utf8String usrSuffix;
|
||||
};
|
||||
|
||||
class ReferencesCollector
|
||||
{
|
||||
public:
|
||||
ReferencesCollector(CXTranslationUnit cxTranslationUnit);
|
||||
~ReferencesCollector();
|
||||
|
||||
ReferencesResult collect(uint line, uint column) const;
|
||||
|
||||
private:
|
||||
bool isWithinTokenRange(CXToken token, uint line, uint column) const;
|
||||
bool pointsToIdentifier(uint line, uint column, unsigned *tokenIndex) const;
|
||||
bool matchesIdentifier(const CXToken &token, const Utf8String &identifier) const;
|
||||
bool checkToken(unsigned index, const Utf8String &identifier, const Utf8String &usr) const;
|
||||
|
||||
private:
|
||||
CXTranslationUnit m_cxTranslationUnit = nullptr;
|
||||
CXToken *m_cxTokens = nullptr;
|
||||
uint m_cxTokenCount = 0;
|
||||
|
||||
QVector<CXCursor> m_cxCursors;
|
||||
};
|
||||
|
||||
ReferencesCollector::ReferencesCollector(CXTranslationUnit cxTranslationUnit)
|
||||
: m_cxTranslationUnit(cxTranslationUnit)
|
||||
{
|
||||
const CXSourceRange range
|
||||
= clang_getCursorExtent(clang_getTranslationUnitCursor(m_cxTranslationUnit));
|
||||
clang_tokenize(cxTranslationUnit, range, &m_cxTokens, &m_cxTokenCount);
|
||||
|
||||
m_cxCursors.resize(static_cast<int>(m_cxTokenCount));
|
||||
clang_annotateTokens(cxTranslationUnit, m_cxTokens, m_cxTokenCount, m_cxCursors.data());
|
||||
}
|
||||
|
||||
ReferencesCollector::~ReferencesCollector()
|
||||
{
|
||||
clang_disposeTokens(m_cxTranslationUnit, m_cxTokens, m_cxTokenCount);
|
||||
}
|
||||
|
||||
bool ReferencesCollector::isWithinTokenRange(CXToken token, uint line, uint column) const
|
||||
{
|
||||
const CXSourceLocation location = clang_getTokenLocation(m_cxTranslationUnit, token);
|
||||
uint candidateLine = 0;
|
||||
uint candiateColumn = 0;
|
||||
clang_getFileLocation(location, nullptr, &candidateLine, &candiateColumn, nullptr);
|
||||
|
||||
const SourceRange range = clang_getTokenExtent(m_cxTranslationUnit, token);
|
||||
return range.contains(line, column);
|
||||
}
|
||||
|
||||
bool ReferencesCollector::pointsToIdentifier(uint line, uint column, unsigned *tokenIndex) const
|
||||
{
|
||||
for (uint i = 0; i < m_cxTokenCount; ++i) {
|
||||
const CXToken token = m_cxTokens[i];
|
||||
if (clang_getTokenKind(token) == CXToken_Identifier
|
||||
&& isWithinTokenRange(token, line, column)) {
|
||||
*tokenIndex = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReferencesCollector::matchesIdentifier(const CXToken &token,
|
||||
const Utf8String &identifier) const
|
||||
{
|
||||
const CXTokenKind tokenKind = clang_getTokenKind(token);
|
||||
if (tokenKind == CXToken_Identifier) {
|
||||
const Utf8String candidateIdentifier
|
||||
= ClangString(clang_getTokenSpelling(m_cxTranslationUnit, token));
|
||||
return candidateIdentifier == identifier;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReferencesCollector::checkToken(unsigned index, const Utf8String &identifier,
|
||||
const Utf8String &usr) const
|
||||
{
|
||||
const CXToken token = m_cxTokens[index];
|
||||
if (!matchesIdentifier(token, identifier))
|
||||
return false;
|
||||
|
||||
{ // For debugging only
|
||||
// const SourceRange range = clang_getTokenExtent(m_cxTranslationUnit, token);
|
||||
// const uint line = range.start().line();
|
||||
// const ClangString spellingCs = clang_getTokenSpelling(m_cxTranslationUnit, token);
|
||||
// const Utf8String spelling = spellingCs;
|
||||
// qWarning() << "ReferencesCollector::checkToken:" << line << spelling;
|
||||
}
|
||||
|
||||
const Cursor currentCursor(m_cxCursors[static_cast<int>(index)]);
|
||||
const ReferencedCursor candidate = ReferencedCursor::find(currentCursor);
|
||||
|
||||
return candidate.usr() == usr;
|
||||
}
|
||||
|
||||
ReferencesResult ReferencesCollector::collect(uint line, uint column) const
|
||||
{
|
||||
ReferencesResult result;
|
||||
|
||||
unsigned index = 0;
|
||||
if (!pointsToIdentifier(line, column, &index))
|
||||
return result;
|
||||
|
||||
const Cursor cursorFromUser = m_cxCursors[static_cast<int>(index)];
|
||||
const ReferencedCursor refCursor = ReferencedCursor::find(cursorFromUser);
|
||||
const Utf8String usr = refCursor.usr();
|
||||
if (usr.isEmpty())
|
||||
return result;
|
||||
|
||||
const CXToken token = m_cxTokens[index];
|
||||
const Utf8String identifier = ClangString(clang_getTokenSpelling(m_cxTranslationUnit, token));
|
||||
for (uint i = 0; i < m_cxTokenCount; ++i) {
|
||||
if (checkToken(i, identifier, usr)) {
|
||||
const SourceRange range = clang_getTokenExtent(m_cxTranslationUnit, m_cxTokens[i]);
|
||||
result.references.append(range);
|
||||
}
|
||||
}
|
||||
|
||||
result.isLocalVariable = refCursor.isLocalVariable();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ReferencesResult collectReferences(CXTranslationUnit cxTranslationUnit,
|
||||
uint line,
|
||||
uint column)
|
||||
{
|
||||
ReferencesCollector collector(cxTranslationUnit);
|
||||
return collector.collect(line, column);
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
52
src/tools/clangbackend/ipcsource/clangreferencescollector.h
Normal file
52
src/tools/clangbackend/ipcsource/clangreferencescollector.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <clangbackendipc/sourcerangecontainer.h>
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
struct ReferencesResult {
|
||||
bool isLocalVariable = false;
|
||||
QVector<SourceRangeContainer> references;
|
||||
|
||||
bool operator==(const ReferencesResult &other) const
|
||||
{
|
||||
return isLocalVariable == other.isLocalVariable
|
||||
&& references == other.references;
|
||||
}
|
||||
};
|
||||
|
||||
ReferencesResult collectReferences(CXTranslationUnit cxTranslationUnit,
|
||||
uint line,
|
||||
uint column);
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangrequestreferencesjob.h"
|
||||
|
||||
#include <clangbackendipc/clangbackendipcdebugutils.h>
|
||||
#include <clangbackendipc/referencesmessage.h>
|
||||
#include <clangbackendipc/clangcodemodelclientinterface.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
static RequestReferencesJob::AsyncResult runAsyncHelper(const TranslationUnit &translationUnit,
|
||||
quint32 line,
|
||||
quint32 column)
|
||||
{
|
||||
TIME_SCOPE_DURATION("RequestReferencesJobRunner");
|
||||
|
||||
return translationUnit.references(line, column);
|
||||
}
|
||||
|
||||
IAsyncJob::AsyncPrepareResult RequestReferencesJob::prepareAsyncRun()
|
||||
{
|
||||
const JobRequest jobRequest = context().jobRequest;
|
||||
QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestReferences,
|
||||
return AsyncPrepareResult());
|
||||
|
||||
try {
|
||||
m_pinnedDocument = context().documentForJobRequest();
|
||||
m_pinnedFileContainer = m_pinnedDocument.fileContainer();
|
||||
|
||||
const TranslationUnit translationUnit
|
||||
= m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit);
|
||||
const quint32 line = jobRequest.line;
|
||||
const quint32 column = jobRequest.column;
|
||||
setRunner([translationUnit, line, column]() {
|
||||
return runAsyncHelper(translationUnit, line, column);
|
||||
});
|
||||
return AsyncPrepareResult{translationUnit.id()};
|
||||
|
||||
} catch (const std::exception &exception) {
|
||||
qWarning() << "Error in RequestReferencesJob::prepareAsyncRun:" << exception.what();
|
||||
return AsyncPrepareResult();
|
||||
}
|
||||
}
|
||||
|
||||
void RequestReferencesJob::finalizeAsyncRun()
|
||||
{
|
||||
if (!context().isOutdated()) {
|
||||
const AsyncResult result = asyncResult();
|
||||
|
||||
const ReferencesMessage message(m_pinnedFileContainer,
|
||||
result.references,
|
||||
result.isLocalVariable,
|
||||
context().jobRequest.ticketNumber);
|
||||
context().client->references(message);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
49
src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h
Normal file
49
src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "clangasyncjob.h"
|
||||
#include "clangreferencescollector.h"
|
||||
#include "clangdocument.h"
|
||||
|
||||
#include <clangbackendipc/sourcerangecontainer.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class RequestReferencesJob : public AsyncJob<ReferencesResult>
|
||||
{
|
||||
public:
|
||||
using AsyncResult = ReferencesResult;
|
||||
|
||||
AsyncPrepareResult prepareAsyncRun() override;
|
||||
void finalizeAsyncRun() override;
|
||||
|
||||
private:
|
||||
Document m_pinnedDocument;
|
||||
FileContainer m_pinnedFileContainer;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
@@ -24,6 +24,8 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangtranslationunit.h"
|
||||
|
||||
#include "clangreferencescollector.h"
|
||||
#include "clangtranslationunitupdater.h"
|
||||
|
||||
#include <codecompleter.h>
|
||||
@@ -122,6 +124,11 @@ void TranslationUnit::extractDocumentAnnotations(
|
||||
skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers();
|
||||
}
|
||||
|
||||
ReferencesResult TranslationUnit::references(uint line, uint column) const
|
||||
{
|
||||
return collectReferences(m_cxTranslationUnit, line, column);
|
||||
}
|
||||
|
||||
DiagnosticSet TranslationUnit::diagnostics() const
|
||||
{
|
||||
return DiagnosticSet(clang_getDiagnosticSetFromTU(m_cxTranslationUnit));
|
||||
|
||||
@@ -40,6 +40,7 @@ class DiagnosticContainer;
|
||||
class DiagnosticSet;
|
||||
class HighlightingMarkContainer;
|
||||
class HighlightingMarks;
|
||||
class ReferencesResult;
|
||||
class SkippedSourceRanges;
|
||||
class SourceLocation;
|
||||
class SourceRange;
|
||||
@@ -83,6 +84,8 @@ public:
|
||||
QVector<HighlightingMarkContainer> &highlightingMarks,
|
||||
QVector<SourceRangeContainer> &skippedSourceRanges) const;
|
||||
|
||||
|
||||
ReferencesResult references(uint line, uint column) const;
|
||||
DiagnosticSet diagnostics() const;
|
||||
|
||||
SourceLocation sourceLocationAt(uint line, uint column) const;
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
bool Type::isValid() const
|
||||
{
|
||||
return cxType.kind != CXType_Invalid;
|
||||
}
|
||||
|
||||
bool Type::isConstant() const
|
||||
{
|
||||
return clang_isConstQualifiedType(cxType);
|
||||
@@ -74,6 +79,11 @@ bool Type::isOutputArgument() const
|
||||
return (isPointer() || isLValueReference()) && !pointeeType().isConstant();
|
||||
}
|
||||
|
||||
bool Type::isBuiltinType() const
|
||||
{
|
||||
return cxType.kind >= CXType_FirstBuiltin && cxType.kind <= CXType_LastBuiltin;
|
||||
}
|
||||
|
||||
Utf8String Type::utf8Spelling() const
|
||||
{
|
||||
return ClangString(clang_getTypeSpelling(cxType));
|
||||
|
||||
@@ -42,6 +42,8 @@ class Type
|
||||
friend bool operator==(Type first, Type second);
|
||||
|
||||
public:
|
||||
bool isValid() const;
|
||||
|
||||
bool isConstant() const;
|
||||
bool isConstantReference();
|
||||
bool isPointer() const;
|
||||
@@ -50,6 +52,7 @@ public:
|
||||
bool isLValueReference() const;
|
||||
bool isReferencingConstant() const;
|
||||
bool isOutputArgument() const;
|
||||
bool isBuiltinType() const;
|
||||
|
||||
Utf8String utf8Spelling() const;
|
||||
ClangString spelling() const;
|
||||
|
||||
@@ -118,6 +118,46 @@ bool Cursor::isLocalVariable() const
|
||||
}
|
||||
}
|
||||
|
||||
bool Cursor::isReference() const
|
||||
{
|
||||
return clang_isReference(kind());
|
||||
}
|
||||
|
||||
bool Cursor::isExpression() const
|
||||
{
|
||||
return clang_isExpression(kind());
|
||||
}
|
||||
|
||||
bool Cursor::isFunctionLike() const
|
||||
{
|
||||
const CXCursorKind k = kind();
|
||||
return k == CXCursor_FunctionDecl
|
||||
|| k == CXCursor_CXXMethod
|
||||
|| k == CXCursor_FunctionTemplate;
|
||||
}
|
||||
|
||||
bool Cursor::isConstructorOrDestructor() const
|
||||
{
|
||||
const CXCursorKind k = kind();
|
||||
return k == CXCursor_Constructor
|
||||
|| k == CXCursor_Destructor;
|
||||
}
|
||||
|
||||
bool Cursor::isTemplateLike() const
|
||||
{
|
||||
switch (kind()) {
|
||||
case CXCursor_ClassTemplate:
|
||||
case CXCursor_ClassTemplatePartialSpecialization:
|
||||
return true;
|
||||
case CXCursor_ClassDecl:
|
||||
return specializedCursorTemplate().isValid();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
bool Cursor::hasFinalFunctionAttribute() const
|
||||
{
|
||||
bool hasFinal = false;
|
||||
@@ -208,6 +248,11 @@ Type Cursor::nonPointerTupe() const
|
||||
return typeResult;
|
||||
}
|
||||
|
||||
Cursor Cursor::specializedCursorTemplate() const
|
||||
{
|
||||
return clang_getSpecializedCursorTemplate(cxCursor);
|
||||
}
|
||||
|
||||
SourceLocation Cursor::sourceLocation() const
|
||||
{
|
||||
return clang_getCursorLocation(cxCursor);
|
||||
|
||||
@@ -62,6 +62,11 @@ public:
|
||||
bool isCompoundType() const;
|
||||
bool isDeclaration() const;
|
||||
bool isLocalVariable() const;
|
||||
bool isReference() const;
|
||||
bool isExpression() const;
|
||||
bool isFunctionLike() const;
|
||||
bool isConstructorOrDestructor() const;
|
||||
bool isTemplateLike() const;
|
||||
bool hasFinalFunctionAttribute() const;
|
||||
bool hasFinalClassAttribute() const;
|
||||
bool isUnexposed() const;
|
||||
@@ -95,6 +100,7 @@ public:
|
||||
Cursor argument(int index) const;
|
||||
unsigned overloadedDeclarationsCount() const;
|
||||
Cursor overloadedDeclaration(unsigned index) const;
|
||||
Cursor specializedCursorTemplate() const;
|
||||
|
||||
void collectOutputArgumentRangesTo(
|
||||
std::vector<CXSourceRange> &outputArgumentRanges) const;
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
SourceRange::SourceRange()
|
||||
@@ -61,6 +63,17 @@ SourceLocation SourceRange::end() const
|
||||
return SourceLocation(clang_getRangeEnd(cxSourceRange));
|
||||
}
|
||||
|
||||
bool SourceRange::contains(unsigned line, unsigned column) const
|
||||
{
|
||||
const SourceLocation start_ = start();
|
||||
const SourceLocation end_ = end();
|
||||
|
||||
return start_.line() <= line
|
||||
&& start_.column() <= column
|
||||
&& line <= end_.line()
|
||||
&& column <= end_.column();
|
||||
}
|
||||
|
||||
SourceRangeContainer SourceRange::toSourceRangeContainer() const
|
||||
{
|
||||
return SourceRangeContainer(start().toSourceLocationContainer(),
|
||||
|
||||
@@ -49,6 +49,8 @@ public:
|
||||
SourceLocation start() const;
|
||||
SourceLocation end() const;
|
||||
|
||||
bool contains(unsigned line, unsigned column) const;
|
||||
|
||||
SourceRangeContainer toSourceRangeContainer() const;
|
||||
|
||||
operator CXSourceRange() const;
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
#include <clangbackendipc/cmbunregistertranslationunitsforeditormessage.h>
|
||||
#include <clangbackendipc/connectionserver.h>
|
||||
#include <clangbackendipc/registerunsavedfilesforeditormessage.h>
|
||||
#include <requestdocumentannotations.h>
|
||||
#include <clangbackendipc/requestdocumentannotations.h>
|
||||
#include <clangbackendipc/requestreferencesmessage.h>
|
||||
#include <clangbackendipc/unregisterunsavedfilesforeditormessage.h>
|
||||
#include <clangbackendipc/updatetranslationunitsforeditormessage.h>
|
||||
#include <clangbackendipc/updatevisibletranslationunitsmessage.h>
|
||||
@@ -102,6 +103,11 @@ void EchoClangCodeModelServer::requestDocumentAnnotations(const RequestDocumentA
|
||||
echoMessage(message);
|
||||
}
|
||||
|
||||
void EchoClangCodeModelServer::requestReferences(const RequestReferencesMessage &message)
|
||||
{
|
||||
echoMessage(message);
|
||||
}
|
||||
|
||||
void EchoClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message)
|
||||
{
|
||||
echoMessage(message);
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
void unregisterUnsavedFilesForEditor(const UnregisterUnsavedFilesForEditorMessage &message) override;
|
||||
void completeCode(const CompleteCodeMessage &message) override;
|
||||
void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override;
|
||||
void requestReferences(const RequestReferencesMessage &message) override;
|
||||
void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
#include <cmbregistertranslationunitsforeditormessage.h>
|
||||
#include <cmbunregisterprojectsforeditormessage.h>
|
||||
#include <cmbunregistertranslationunitsforeditormessage.h>
|
||||
#include <requestreferencesmessage.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
@@ -128,6 +131,7 @@ protected:
|
||||
void updateVisibilty(const Utf8String ¤tEditor, const Utf8String &additionalVisibleEditor);
|
||||
|
||||
void requestDocumentAnnotations(const Utf8String &filePath);
|
||||
void requestReferences(quint32 documentRevision = 0);
|
||||
|
||||
void completeCode(const Utf8String &filePath, uint line = 1, uint column = 1,
|
||||
const Utf8String &projectPartId = Utf8String());
|
||||
@@ -136,6 +140,8 @@ protected:
|
||||
|
||||
bool isSupportiveTranslationUnitInitialized(const Utf8String &filePath);
|
||||
|
||||
DocumentProcessor documentProcessorForFile(const Utf8String &filePath);
|
||||
|
||||
void expectDocumentAnnotationsChanged(int count);
|
||||
void expectCompletion(const CodeCompletion &completion);
|
||||
void expectCompletionFromFileA();
|
||||
@@ -143,6 +149,7 @@ protected:
|
||||
void expectCompletionFromFileAUnsavedMethodVersion1();
|
||||
void expectCompletionFromFileAUnsavedMethodVersion2();
|
||||
void expectNoCompletionWithUnsavedMethod();
|
||||
void expectReferences();
|
||||
void expectDocumentAnnotationsChangedForFileBWithSpecificHighlightingMark();
|
||||
|
||||
static const Utf8String unsavedContent(const QString &unsavedFilePath);
|
||||
@@ -160,6 +167,7 @@ protected:
|
||||
= QStringLiteral(TESTDATA_DIR) + QStringLiteral("/complete_extractor_function_unsaved_2.cpp");
|
||||
|
||||
const Utf8String filePathB = Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_variable.cpp");
|
||||
const Utf8String filePathC = Utf8StringLiteral(TESTDATA_DIR"/references.cpp");
|
||||
|
||||
const Utf8String aFilePath = Utf8StringLiteral("afile.cpp");
|
||||
const Utf8String anExistingFilePath
|
||||
@@ -185,6 +193,25 @@ TEST_F(ClangCodeModelServerSlowTest, RequestDocumentAnnotations)
|
||||
requestDocumentAnnotations(filePathB);
|
||||
}
|
||||
|
||||
TEST_F(ClangCodeModelServerSlowTest, RequestReferencesForCurrentDocumentRevision)
|
||||
{
|
||||
registerProjectAndFileAndWaitForFinished(filePathC);
|
||||
|
||||
expectReferences();
|
||||
requestReferences();
|
||||
}
|
||||
|
||||
TEST_F(ClangCodeModelServerSlowTest, RequestReferencesTakesRevisionFromMessage)
|
||||
{
|
||||
registerProjectAndFileAndWaitForFinished(filePathC);
|
||||
|
||||
requestReferences(/*documentRevision=*/ 99);
|
||||
|
||||
JobRequests &queue = documentProcessorForFile(filePathC).queue();
|
||||
Utils::anyOf(queue, [](const JobRequest &request) { return request.documentRevision == 99; });
|
||||
queue.clear(); // Avoid blocking
|
||||
}
|
||||
|
||||
TEST_F(ClangCodeModelServerSlowTest, NoInitialDocumentAnnotationsForClosedDocument)
|
||||
{
|
||||
const int expectedDocumentAnnotationsChangedCount = 0;
|
||||
@@ -462,7 +489,15 @@ bool ClangCodeModelServer::isSupportiveTranslationUnitInitialized(const Utf8Stri
|
||||
|
||||
return document.translationUnits().size() == 2
|
||||
&& documentProcessor.hasSupportiveTranslationUnit()
|
||||
&& documentProcessor.isSupportiveTranslationUnitInitialized();
|
||||
&& documentProcessor.isSupportiveTranslationUnitInitialized();
|
||||
}
|
||||
|
||||
DocumentProcessor ClangCodeModelServer::documentProcessorForFile(const Utf8String &filePath)
|
||||
{
|
||||
Document document = clangServer.documentsForTestOnly().document(filePath, projectPartId);
|
||||
DocumentProcessor documentProcessor = clangServer.documentProcessors().processor(document);
|
||||
|
||||
return documentProcessor;
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::expectCompletion(const CodeCompletion &completion)
|
||||
@@ -512,6 +547,20 @@ void ClangCodeModelServer::expectNoCompletionWithUnsavedMethod()
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::expectReferences()
|
||||
{
|
||||
const QVector<ClangBackEnd::SourceRangeContainer> references{{
|
||||
{filePathC, 3, 9},
|
||||
{filePathC, 3, 12}
|
||||
}};
|
||||
|
||||
EXPECT_CALL(mockClangCodeModelClient,
|
||||
references(
|
||||
Property(&ReferencesMessage::references,
|
||||
Eq(references))))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::expectCompletionFromFileA()
|
||||
{
|
||||
const CodeCompletion completion(Utf8StringLiteral("Function"),
|
||||
@@ -528,6 +577,15 @@ void ClangCodeModelServer::requestDocumentAnnotations(const Utf8String &filePath
|
||||
clangServer.requestDocumentAnnotations(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::requestReferences(quint32 documentRevision)
|
||||
{
|
||||
const FileContainer fileContainer{filePathC, projectPartId, Utf8StringVector(),
|
||||
documentRevision};
|
||||
const RequestReferencesMessage message{fileContainer, 3, 9};
|
||||
|
||||
clangServer.requestReferences(message);
|
||||
}
|
||||
|
||||
void ClangCodeModelServer::expectDocumentAnnotationsChangedForFileBWithSpecificHighlightingMark()
|
||||
{
|
||||
HighlightingTypes types;
|
||||
|
||||
@@ -65,6 +65,9 @@ protected:
|
||||
JobRequest::Type type,
|
||||
PreferredTranslationUnit preferredTranslationUnit
|
||||
= PreferredTranslationUnit::RecentlyParsed) const;
|
||||
JobRequest createJobRequestWithConditions(const Utf8String &filePath,
|
||||
JobRequest::Type type,
|
||||
JobRequest::Conditions conditions) const;
|
||||
|
||||
void updateDocumentRevision();
|
||||
void updateUnsavedFiles();
|
||||
@@ -410,6 +413,30 @@ TEST_F(JobQueue, RequestCompleteCodeOutdatableByDocumentRevisionChange)
|
||||
ASSERT_THAT(jobsToStart.size(), Eq(0));
|
||||
}
|
||||
|
||||
TEST_F(JobQueue, RequestReferencesRunsForCurrentDocumentRevision)
|
||||
{
|
||||
jobQueue.add( createJobRequestWithConditions(filePath1,
|
||||
JobRequest::Type::RequestReferences,
|
||||
JobRequest::Condition::CurrentDocumentRevision));
|
||||
|
||||
const JobRequests jobsToStart = jobQueue.processQueue();
|
||||
|
||||
ASSERT_THAT(jobsToStart.size(), Eq(1));
|
||||
}
|
||||
|
||||
TEST_F(JobQueue, RequestReferencesOutdatableByDocumentClose)
|
||||
{
|
||||
jobQueue.add(createJobRequestWithConditions(filePath1,
|
||||
JobRequest::Type::RequestReferences,
|
||||
JobRequest::Condition::CurrentDocumentRevision));
|
||||
removeDocument();
|
||||
|
||||
const JobRequests jobsToStart = jobQueue.processQueue();
|
||||
|
||||
ASSERT_THAT(jobsToStart.size(), Eq(0));
|
||||
ASSERT_THAT(jobQueue.size(), Eq(0));
|
||||
}
|
||||
|
||||
void JobQueue::SetUp()
|
||||
{
|
||||
projects.createOrUpdate({ProjectPartContainer(projectPartId)});
|
||||
@@ -460,6 +487,18 @@ JobRequest JobQueue::createJobRequest(
|
||||
return jobRequest;
|
||||
}
|
||||
|
||||
JobRequest JobQueue::createJobRequestWithConditions(const Utf8String &filePath,
|
||||
JobRequest::Type type,
|
||||
JobRequest::Conditions conditions) const
|
||||
{
|
||||
JobRequest jobRequest = createJobRequest(filePath,
|
||||
type,
|
||||
PreferredTranslationUnit::RecentlyParsed);
|
||||
jobRequest.conditions = conditions;
|
||||
|
||||
return jobRequest;
|
||||
}
|
||||
|
||||
void JobQueue::updateDocumentRevision()
|
||||
{
|
||||
documents.update({FileContainer(filePath1, projectPartId, Utf8String(), true, 1)});
|
||||
|
||||
@@ -56,7 +56,7 @@ protected:
|
||||
void TearDown() override;
|
||||
|
||||
bool waitUntilAllJobsFinished(int timeOutInMs = 10000) const;
|
||||
bool waitUntilJobChainFinished(int timeOutInMs = 10000) const;
|
||||
bool waitUntilJobChainFinished(int timeOutInMs = 10000);
|
||||
|
||||
protected:
|
||||
ClangBackEnd::ProjectParts projects;
|
||||
@@ -134,7 +134,7 @@ bool Jobs::waitUntilAllJobsFinished(int timeOutInMs) const
|
||||
return ProcessEventUtilities::processEventsUntilTrue(noJobsRunningAnymore, timeOutInMs);
|
||||
}
|
||||
|
||||
bool Jobs::waitUntilJobChainFinished(int timeOutInMs) const
|
||||
bool Jobs::waitUntilJobChainFinished(int timeOutInMs)
|
||||
{
|
||||
const auto noJobsRunningAnymore = [this]() {
|
||||
return jobs.runningJobs().isEmpty() && jobs.queue().isEmpty();
|
||||
|
||||
479
tests/unit/unittest/clangreferencescollector-test.cpp
Normal file
479
tests/unit/unittest/clangreferencescollector-test.cpp
Normal file
@@ -0,0 +1,479 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include <clangbackendipc_global.h>
|
||||
#include <clangreferencescollector.h>
|
||||
#include <clangdocument.h>
|
||||
#include <clangdocuments.h>
|
||||
#include <clangtranslationunit.h>
|
||||
#include <fixitcontainer.h>
|
||||
#include <projectpart.h>
|
||||
#include <projects.h>
|
||||
#include <sourcelocationcontainer.h>
|
||||
#include <sourcerangecontainer.h>
|
||||
#include <unsavedfiles.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
using ::testing::Contains;
|
||||
using ::testing::Not;
|
||||
using ::testing::ContainerEq;
|
||||
using ::testing::Eq;
|
||||
|
||||
using ::ClangBackEnd::ProjectPart;
|
||||
using ::ClangBackEnd::SourceLocationContainer;
|
||||
using ::ClangBackEnd::Document;
|
||||
using ::ClangBackEnd::UnsavedFiles;
|
||||
using ::ClangBackEnd::ReferencesResult;
|
||||
using ::ClangBackEnd::SourceRangeContainer;
|
||||
|
||||
using References = QVector<SourceRangeContainer>;
|
||||
|
||||
namespace {
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const ReferencesResult &value)
|
||||
{
|
||||
os << "ReferencesResult(";
|
||||
os << value.isLocalVariable << ", {";
|
||||
for (const SourceRangeContainer &r : value.references) {
|
||||
os << r.start().line() << ",";
|
||||
os << r.start().column() << ",";
|
||||
QTC_CHECK(r.start().line() == r.end().line());
|
||||
os << r.end().column() - r.start().column() << ",";
|
||||
}
|
||||
os << "})";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
struct Data {
|
||||
Data()
|
||||
{
|
||||
document.parse();
|
||||
}
|
||||
|
||||
ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++14")}};
|
||||
ClangBackEnd::ProjectParts projects;
|
||||
ClangBackEnd::UnsavedFiles unsavedFiles;
|
||||
ClangBackEnd::Documents documents{projects, unsavedFiles};
|
||||
Document document{Utf8StringLiteral(TESTDATA_DIR"/references.cpp"),
|
||||
projectPart,
|
||||
Utf8StringVector(),
|
||||
documents};
|
||||
};
|
||||
|
||||
class ReferencesCollector : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
ReferencesResult getReferences(uint line, uint column)
|
||||
{
|
||||
return d->document.translationUnit().references(line, column);
|
||||
}
|
||||
|
||||
SourceLocationContainer createSourceLocation(uint line, uint column) const
|
||||
{
|
||||
return SourceLocationContainer(d->document.filePath(), line, column);
|
||||
}
|
||||
|
||||
SourceRangeContainer createSourceRange(uint line, uint column, uint length) const
|
||||
{
|
||||
return SourceRangeContainer {
|
||||
createSourceLocation(line, column),
|
||||
createSourceLocation(line, column + length)
|
||||
};
|
||||
}
|
||||
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
private:
|
||||
static std::unique_ptr<Data> d;
|
||||
};
|
||||
|
||||
// This test is not strictly needed as the plugin is supposed to put the cursor
|
||||
// on the identifier start.
|
||||
TEST_F(ReferencesCollector, CursorNotOnIdentifier)
|
||||
{
|
||||
const ReferencesResult expected { false, {}, };
|
||||
|
||||
const ReferencesResult actual = getReferences(3, 5);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, LocalVariableWithSingleUse)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(3, 9, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(3, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, LocalVariableWithTwoUses)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(10, 9, 3),
|
||||
createSourceRange(11, 12, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(10, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ClassName)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(16, 7, 3),
|
||||
createSourceRange(19, 5, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(16, 7);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, Namespace)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(24, 11, 1),
|
||||
createSourceRange(25, 11, 1),
|
||||
createSourceRange(26, 1, 1)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(24, 11);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ClassNameDeclaredWithUsing)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(30, 21, 3),
|
||||
createSourceRange(31, 10, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(30, 21);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ClassNameForwardDeclared)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(35, 7, 3),
|
||||
createSourceRange(36, 14, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(35, 7);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ClassNameAndNewExpression)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(40, 7, 3),
|
||||
createSourceRange(43, 9, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(40, 7);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, InstantiatedTemplateObject)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(52, 19, 3),
|
||||
createSourceRange(53, 5, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(52, 19);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, VariableInTemplate)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(62, 13, 3),
|
||||
createSourceRange(63, 11, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(62, 13);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, MemberInTemplate)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(64, 16, 3),
|
||||
createSourceRange(67, 7, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(67, 7);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, TemplateType)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(58, 19, 1),
|
||||
createSourceRange(60, 5, 1),
|
||||
createSourceRange(67, 5, 1)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(58, 19);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, MemberAccessIntoTemplateParameter)
|
||||
{
|
||||
const ReferencesResult expected { false, {}, };
|
||||
|
||||
const ReferencesResult actual = getReferences(76, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ConstructorAsType)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(81, 8, 3),
|
||||
createSourceRange(82, 5, 3),
|
||||
createSourceRange(83, 6, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(82, 5);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, OverloadsFreeStanding)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(88, 5, 3),
|
||||
createSourceRange(89, 5, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(88, 5);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, OverloadsMemberFunctions)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(94, 9, 3),
|
||||
createSourceRange(95, 9, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(94, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, FunctionAndTemplateFunction)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(100, 26, 3),
|
||||
createSourceRange(101, 5, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(100, 26);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, FunctionAndTemplateFunctionAsMember)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(106, 30, 3),
|
||||
createSourceRange(107, 9, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(106, 30);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, EnumType)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(112, 6, 2),
|
||||
createSourceRange(113, 8, 2)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(112, 6);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, LambdaCapturedObject)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(122, 15, 3),
|
||||
createSourceRange(122, 33, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(122, 15);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
//// Disabled because it looks like the lambda initializer is not yet exposed by libclang.
|
||||
TEST_F(ReferencesCollector, DISABLED_LambdaCaptureInitializer)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(121, 19, 3),
|
||||
createSourceRange(122, 19, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(122, 19);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, TemplateSpecialization)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(127, 25, 3),
|
||||
createSourceRange(128, 25, 3),
|
||||
createSourceRange(129, 18, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(127, 25);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, TemplateDependentName)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(133, 34, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(133, 34);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, FunctionCallAndDefinition)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(140, 5, 3),
|
||||
createSourceRange(142, 25, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(140, 5);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ObjectLikeMacro)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(147, 9, 3),
|
||||
createSourceRange(150, 12, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(147, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, FunctionLikeMacro)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
false,
|
||||
{createSourceRange(155, 9, 3),
|
||||
createSourceRange(158, 12, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(155, 9);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
TEST_F(ReferencesCollector, ArgumentToFunctionLikeMacro)
|
||||
{
|
||||
const ReferencesResult expected {
|
||||
true,
|
||||
{createSourceRange(156, 27, 3),
|
||||
createSourceRange(158, 16, 3)},
|
||||
};
|
||||
|
||||
const ReferencesResult actual = getReferences(156, 27);
|
||||
|
||||
ASSERT_THAT(actual, expected);
|
||||
}
|
||||
|
||||
std::unique_ptr<Data> ReferencesCollector::d;
|
||||
|
||||
void ReferencesCollector::SetUpTestCase()
|
||||
{
|
||||
d.reset(new Data);
|
||||
}
|
||||
|
||||
void ReferencesCollector::TearDownTestCase()
|
||||
{
|
||||
d.reset();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
114
tests/unit/unittest/clangrequestreferencesjob-test.cpp
Normal file
114
tests/unit/unittest/clangrequestreferencesjob-test.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "clangasyncjob-base.h"
|
||||
|
||||
#include <clangrequestreferencesjob.h>
|
||||
|
||||
using namespace ClangBackEnd;
|
||||
|
||||
using testing::_;
|
||||
using testing::Eq;
|
||||
using testing::Property;
|
||||
|
||||
namespace {
|
||||
|
||||
class RequestReferencesJob : public ClangAsyncJobTest
|
||||
{
|
||||
protected:
|
||||
void SetUp() override { BaseSetUp(JobRequest::Type::RequestReferences, job); }
|
||||
|
||||
protected:
|
||||
ClangBackEnd::RequestReferencesJob job;
|
||||
};
|
||||
|
||||
TEST_F(RequestReferencesJob, PrepareAsyncRun)
|
||||
{
|
||||
job.setContext(jobContext);
|
||||
|
||||
ASSERT_TRUE(job.prepareAsyncRun());
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, RunAsync)
|
||||
{
|
||||
job.setContext(jobContext);
|
||||
job.prepareAsyncRun();
|
||||
|
||||
job.runAsync();
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, SendReferences)
|
||||
{
|
||||
job.setContext(jobContextWithMockClient);
|
||||
job.prepareAsyncRun();
|
||||
EXPECT_CALL(mockIpcClient, references(_)).Times(1);
|
||||
|
||||
job.runAsync();
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, ForwardTicketNumber)
|
||||
{
|
||||
jobRequest.ticketNumber = static_cast<quint64>(99);
|
||||
jobContextWithMockClient = JobContext(jobRequest, &documents, &unsavedFiles, &mockIpcClient);
|
||||
job.setContext(jobContextWithMockClient);
|
||||
job.prepareAsyncRun();
|
||||
EXPECT_CALL(mockIpcClient,
|
||||
references(Property(&ReferencesMessage::ticketNumber, Eq(99))))
|
||||
.Times(1);
|
||||
|
||||
job.runAsync();
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, DontSendReferencesIfDocumentWasClosed)
|
||||
{
|
||||
job.setContext(jobContextWithMockClient);
|
||||
job.prepareAsyncRun();
|
||||
EXPECT_CALL(mockIpcClient, references(_)).Times(0);
|
||||
|
||||
job.runAsync();
|
||||
documents.remove({FileContainer{filePath, projectPartId}});
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(RequestReferencesJob, DontSendReferencesIfDocumentRevisionChanged)
|
||||
{
|
||||
job.setContext(jobContextWithMockClient);
|
||||
job.prepareAsyncRun();
|
||||
EXPECT_CALL(mockIpcClient, references(_)).Times(0);
|
||||
|
||||
job.runAsync();
|
||||
documents.update({FileContainer(filePath, projectPartId, Utf8String(), true, 99)});
|
||||
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <readmessageblock.h>
|
||||
#include <registerunsavedfilesforeditormessage.h>
|
||||
#include <requestdocumentannotations.h>
|
||||
#include <requestreferencesmessage.h>
|
||||
#include <translationunitdoesnotexistmessage.h>
|
||||
#include <unregisterunsavedfilesforeditormessage.h>
|
||||
#include <updatetranslationunitsforeditormessage.h>
|
||||
|
||||
159
tests/unit/unittest/data/references.cpp
Normal file
159
tests/unit/unittest/data/references.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
void variableSingleReference()
|
||||
{
|
||||
int foo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int variableMultipleReferences()
|
||||
{
|
||||
int foo = 0;
|
||||
return foo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Foo {};
|
||||
void bla()
|
||||
{
|
||||
Foo foo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace N { class Bar {}; }
|
||||
namespace N { class Baz {}; }
|
||||
N::Bar bar;
|
||||
|
||||
|
||||
|
||||
namespace G { class App {}; }
|
||||
using G::App;
|
||||
|
||||
|
||||
|
||||
class Hoo;
|
||||
void f(const Hoo &);
|
||||
|
||||
|
||||
|
||||
class Moo {};
|
||||
void x()
|
||||
{
|
||||
new Moo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class Element {};
|
||||
template<typename T> struct Wrap { T member; };
|
||||
void g()
|
||||
{
|
||||
Wrap<Element> con;
|
||||
con.member;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct Wrapper {
|
||||
T f()
|
||||
{
|
||||
int foo;
|
||||
++foo;
|
||||
return mem;
|
||||
}
|
||||
|
||||
T mem;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
void f()
|
||||
{
|
||||
T mem;
|
||||
mem.foo();
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Woo {
|
||||
Woo();
|
||||
~Woo();
|
||||
};
|
||||
|
||||
|
||||
|
||||
int muu();
|
||||
int muu(int);
|
||||
|
||||
|
||||
|
||||
struct Doo {
|
||||
int muu();
|
||||
int muu(int);
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T> int tuu();
|
||||
int tuu(int);
|
||||
|
||||
|
||||
|
||||
struct Xoo {
|
||||
template<typename T> int tuu();
|
||||
int tuu(int);
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum ET { E1 };
|
||||
bool e(ET e)
|
||||
{
|
||||
return e == E1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct LData { int member; };
|
||||
void lambda(LData foo) {
|
||||
auto l = [bar=foo] { return bar.member; };
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T> class Coo;
|
||||
template<class T> class Coo<T*>;
|
||||
template<> class Coo<int>;
|
||||
|
||||
|
||||
|
||||
template<typename T> typename T::foo n()
|
||||
{
|
||||
typename T::bla hello;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int rec(int n = 100)
|
||||
{
|
||||
return n == 0 ? 0 : rec(--n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define FOO 3
|
||||
int objectLikeMacro()
|
||||
{
|
||||
return FOO;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define BAR(x) x
|
||||
int functionLikeMacro(int foo)
|
||||
{
|
||||
return BAR(foo);
|
||||
}
|
||||
@@ -38,4 +38,5 @@ public:
|
||||
void translationUnitDoesNotExist(const ClangBackEnd::TranslationUnitDoesNotExistMessage &) override {}
|
||||
void projectPartsDoNotExist(const ClangBackEnd::ProjectPartsDoNotExistMessage &) override {}
|
||||
void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &) override {}
|
||||
void references(const ClangBackEnd::ReferencesMessage &) override {}
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <clangbackendipc/cmbcodecompletedmessage.h>
|
||||
#include <clangbackendipc/cmbechomessage.h>
|
||||
#include <clangbackendipc/documentannotationschangedmessage.h>
|
||||
#include <clangbackendipc/referencesmessage.h>
|
||||
#include <clangbackendipc/projectpartsdonotexistmessage.h>
|
||||
#include <clangbackendipc/translationunitdoesnotexistmessage.h>
|
||||
#include <clangbackendipc/updatetranslationunitsforeditormessage.h>
|
||||
@@ -51,4 +52,6 @@ public:
|
||||
void(const ClangBackEnd::ProjectPartsDoNotExistMessage &message));
|
||||
MOCK_METHOD1(documentAnnotationsChanged,
|
||||
void(const ClangBackEnd::DocumentAnnotationsChangedMessage &message));
|
||||
MOCK_METHOD1(references,
|
||||
void(const ClangBackEnd::ReferencesMessage &message));
|
||||
};
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
void(const ClangBackEnd::CompleteCodeMessage &message));
|
||||
MOCK_METHOD1(requestDocumentAnnotations,
|
||||
void(const ClangBackEnd::RequestDocumentAnnotationsMessage &message));
|
||||
MOCK_METHOD1(requestReferences,
|
||||
void(const ClangBackEnd::RequestReferencesMessage &message));
|
||||
MOCK_METHOD1(updateVisibleTranslationUnits,
|
||||
void(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message));
|
||||
};
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <highlightingmarkcontainer.h>
|
||||
#include <messageenvelop.h>
|
||||
#include <requestdocumentannotations.h>
|
||||
#include <requestreferencesmessage.h>
|
||||
#include <referencesmessage.h>
|
||||
#include <readmessageblock.h>
|
||||
#include <registerunsavedfilesforeditormessage.h>
|
||||
#include <unregisterunsavedfilesforeditormessage.h>
|
||||
@@ -206,6 +208,21 @@ TEST_F(ReadAndWriteMessageBlock, CompareRequestDocumentAnnotations)
|
||||
CompareMessage(ClangBackEnd::RequestDocumentAnnotationsMessage(fileContainer));
|
||||
}
|
||||
|
||||
TEST_F(ReadAndWriteMessageBlock, CompareRequestReferences)
|
||||
{
|
||||
CompareMessage(ClangBackEnd::RequestReferencesMessage{fileContainer, 13, 37});
|
||||
}
|
||||
|
||||
TEST_F(ReadAndWriteMessageBlock, CompareReferences)
|
||||
{
|
||||
const QVector<ClangBackEnd::SourceRangeContainer> references{
|
||||
true,
|
||||
{{fileContainer.filePath(), 12, 34},
|
||||
{fileContainer.filePath(), 56, 78}}
|
||||
};
|
||||
CompareMessage(ClangBackEnd::ReferencesMessage(fileContainer, references, true, 1));
|
||||
}
|
||||
|
||||
TEST_F(ReadAndWriteMessageBlock, GetInvalidMessageForAPartialBuffer)
|
||||
{
|
||||
writeCodeCompletedMessage();
|
||||
|
||||
@@ -85,6 +85,8 @@ SOURCES += \
|
||||
clangjobqueue-test.cpp \
|
||||
clangjobs-test.cpp \
|
||||
clangrequestdocumentannotationsjob-test.cpp \
|
||||
clangrequestreferencesjob-test.cpp \
|
||||
clangreferencescollector-test.cpp \
|
||||
clangstring-test.cpp \
|
||||
clangtranslationunit-test.cpp \
|
||||
clangtranslationunits-test.cpp \
|
||||
|
||||
Reference in New Issue
Block a user