diff --git a/src/libs/clangbackendipc/clangbackendipc-lib.pri b/src/libs/clangbackendipc/clangbackendipc-lib.pri
index e6d44d4bcc7cbcde5c6c9597259a5336eeab42a7..084c2e8b3a0ea0289580b79ecfa735408d77d313 100644
--- a/src/libs/clangbackendipc/clangbackendipc-lib.pri
+++ b/src/libs/clangbackendipc/clangbackendipc-lib.pri
@@ -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 \
diff --git a/src/libs/clangbackendipc/clangbackendipc_global.h b/src/libs/clangbackendipc/clangbackendipc_global.h
index 1392840fab172534d5663652f1d0bfb26ccb15b2..8f7f08a6eeb2dcbef3ebfe271c73d5269e42b08c 100644
--- a/src/libs/clangbackendipc/clangbackendipc_global.h
+++ b/src/libs/clangbackendipc/clangbackendipc_global.h
@@ -113,6 +113,9 @@ enum class MessageType : quint8 {
     RequestDocumentAnnotationsMessage,
     DocumentAnnotationsChangedMessage,
 
+    RequestReferencesMessage,
+    ReferencesMessage,
+
     UpdateVisibleTranslationUnitsMessage,
 
     CompleteCodeMessage,
diff --git a/src/libs/clangbackendipc/clangcodemodelclientinterface.cpp b/src/libs/clangbackendipc/clangcodemodelclientinterface.cpp
index a817e2f4146a7ecc7ed1b2ec829a65ae6d79cdb6..d01cf18bc05b705e09e0050533d13e8ff44c6e07 100644
--- a/src/libs/clangbackendipc/clangcodemodelclientinterface.cpp
+++ b/src/libs/clangbackendipc/clangcodemodelclientinterface.cpp
@@ -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";
     }
diff --git a/src/libs/clangbackendipc/clangcodemodelclientinterface.h b/src/libs/clangbackendipc/clangcodemodelclientinterface.h
index e532da8b5037669982194a4bb2fde34c6e396097..c451b4a4c938d43b32363936492a665557037248 100644
--- a/src/libs/clangbackendipc/clangcodemodelclientinterface.h
+++ b/src/libs/clangbackendipc/clangcodemodelclientinterface.h
@@ -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
diff --git a/src/libs/clangbackendipc/clangcodemodelclientproxy.cpp b/src/libs/clangbackendipc/clangcodemodelclientproxy.cpp
index 953aa49be09565f1c50e13e932bdcfa5b93c8272..70833f0b77fdd8f6b29518243049a1348c32faa6 100644
--- a/src/libs/clangbackendipc/clangcodemodelclientproxy.cpp
+++ b/src/libs/clangbackendipc/clangcodemodelclientproxy.cpp
@@ -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())
diff --git a/src/libs/clangbackendipc/clangcodemodelclientproxy.h b/src/libs/clangbackendipc/clangcodemodelclientproxy.h
index 005fe30dfa25d0c01908e19755ee6a27888eb172..689f968476860c536e9a5c46edd8b455eb4b6802 100644
--- a/src/libs/clangbackendipc/clangcodemodelclientproxy.h
+++ b/src/libs/clangbackendipc/clangcodemodelclientproxy.h
@@ -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();
 
diff --git a/src/libs/clangbackendipc/clangcodemodelserverinterface.cpp b/src/libs/clangbackendipc/clangcodemodelserverinterface.cpp
index aa94132b8a45a6b1473e4fb921bff7ae952d0d7c..a2c501be3d11164e3be6881fa5b266f24af65fd0 100644
--- a/src/libs/clangbackendipc/clangcodemodelserverinterface.cpp
+++ b/src/libs/clangbackendipc/clangcodemodelserverinterface.cpp
@@ -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;
diff --git a/src/libs/clangbackendipc/clangcodemodelserverinterface.h b/src/libs/clangbackendipc/clangcodemodelserverinterface.h
index 0e0086da4f3d1624d9ebe80c6175b27733afee46..e25b9ef66b59089ea926d4ff1aa0a2388e20805e 100644
--- a/src/libs/clangbackendipc/clangcodemodelserverinterface.h
+++ b/src/libs/clangbackendipc/clangcodemodelserverinterface.h
@@ -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;
 };
 
diff --git a/src/libs/clangbackendipc/clangcodemodelserverproxy.cpp b/src/libs/clangbackendipc/clangcodemodelserverproxy.cpp
index aaf91927352315ba551498093baac128002b98d4..f743f8342aaa81bb8eb8c21a06ed82b27b59285b 100644
--- a/src/libs/clangbackendipc/clangcodemodelserverproxy.cpp
+++ b/src/libs/clangbackendipc/clangcodemodelserverproxy.cpp
@@ -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);
diff --git a/src/libs/clangbackendipc/clangcodemodelserverproxy.h b/src/libs/clangbackendipc/clangcodemodelserverproxy.h
index 57421a190741be8777891e8397ff300e39767930..a854225ffc05bc3b924ce03240cf090114103e1c 100644
--- a/src/libs/clangbackendipc/clangcodemodelserverproxy.h
+++ b/src/libs/clangbackendipc/clangcodemodelserverproxy.h
@@ -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();
diff --git a/src/libs/clangbackendipc/messageenvelop.cpp b/src/libs/clangbackendipc/messageenvelop.cpp
index 5922f26642d4a5f3373b9fab25ac3bd71e412f73..c528dcd69ab0cc7cc693c694ca3adcecd5d90ed5 100644
--- a/src/libs/clangbackendipc/messageenvelop.cpp
+++ b/src/libs/clangbackendipc/messageenvelop.cpp
@@ -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;
diff --git a/src/libs/clangbackendipc/referencesmessage.cpp b/src/libs/clangbackendipc/referencesmessage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8b994a7d7cfaf9106c360b48699a713d6c1d040a
--- /dev/null
+++ b/src/libs/clangbackendipc/referencesmessage.cpp
@@ -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
diff --git a/src/libs/clangbackendipc/referencesmessage.h b/src/libs/clangbackendipc/referencesmessage.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d0b4d292a1054e53b9774ef67d00b2a36345640
--- /dev/null
+++ b/src/libs/clangbackendipc/referencesmessage.h
@@ -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
diff --git a/src/libs/clangbackendipc/requestreferencesmessage.cpp b/src/libs/clangbackendipc/requestreferencesmessage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0527db59d6eb8b8b78e639530561562b5ddd9cfc
--- /dev/null
+++ b/src/libs/clangbackendipc/requestreferencesmessage.cpp
@@ -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
diff --git a/src/libs/clangbackendipc/requestreferencesmessage.h b/src/libs/clangbackendipc/requestreferencesmessage.h
new file mode 100644
index 0000000000000000000000000000000000000000..8d76c1c5afd8ac2e28cde68cfb717c458cd1c2b7
--- /dev/null
+++ b/src/libs/clangbackendipc/requestreferencesmessage.h
@@ -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
diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp
index 54a31a66622a3a418646e3a6fc48d2f3dfa4a8e1..cff37a1625c37aac6d60d328f72d1754978c5ca1 100644
--- a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp
+++ b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp
@@ -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);
diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.h b/src/plugins/clangcodemodel/clangbackendipcintegration.h
index f73f8035d9fcf4c249d55b080a691cdd7bd2e389..6bbd692e9118c78b75f7d78730f6c96d0d7afc8f 100644
--- a/src/plugins/clangcodemodel/clangbackendipcintegration.h
+++ b/src/plugins/clangcodemodel/clangbackendipcintegration.h
@@ -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,
diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
index c0722a3907da1544291044bfa5338d94480b1ebe..800d4baf0e22c6d5d94949c55953e58d2664851e 100644
--- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
+++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp
@@ -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 &params)
 {
-    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)
diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h
index 4760e8bb36c97b9b1ffb056c17df55543d8ce4e5..cdee5b7d8616054b3361e2fef445a70ca9b7cec6 100644
--- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h
+++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h
@@ -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;
diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
index f06753ebc63f583ce0256b997916a43a36345d1c..40296db5639b98500f3ac7ec6f953bac7c094a10 100644
--- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
+++ b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp
@@ -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)); }
 
diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.cpp b/src/plugins/cppeditor/cppuseselectionsupdater.cpp
index bc6530fe0580e5d8b46d78e02623bb3d9085bcdd..217a58fa1d290cbcdd14bcc0929cd9bf84bbf8c2 100644
--- a/src/plugins/cppeditor/cppuseselectionsupdater.cpp
+++ b/src/plugins/cppeditor/cppuseselectionsupdater.cpp
@@ -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());
     }
diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
index cf0a0e6682eb4b0c7b9453a4a2cf03a06687711d..c598eece8b50646e3052d83e7978b596fba0179a 100644
--- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
+++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
@@ -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
diff --git a/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp b/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp
index d310aa523dca98f68cb208a6e5fc0bbabd352b0a..1f6c3263a3456d01b037f9c96fd23cec52d48a96 100644
--- a/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp
+++ b/src/tools/clangbackend/ipcsource/clangcodemodelserver.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");
diff --git a/src/tools/clangbackend/ipcsource/clangcodemodelserver.h b/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
index 90e7191423e89b147561ca019c584f5f4d5240f4..70d99b5afa312852c9545f2bf93ecfc4d6cdea2b 100644
--- a/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
+++ b/src/tools/clangbackend/ipcsource/clangcodemodelserver.h
@@ -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;
diff --git a/src/tools/clangbackend/ipcsource/clangdocumentprocessor.cpp b/src/tools/clangbackend/ipcsource/clangdocumentprocessor.cpp
index fdefb9ab447a48a3d238e340e722b5cf8b060dc5..1aa5906214623dfd639eac000d140f343808232c 100644
--- a/src/tools/clangbackend/ipcsource/clangdocumentprocessor.cpp
+++ b/src/tools/clangbackend/ipcsource/clangdocumentprocessor.cpp
@@ -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();
diff --git a/src/tools/clangbackend/ipcsource/clangdocumentprocessor.h b/src/tools/clangbackend/ipcsource/clangdocumentprocessor.h
index dc193f836280cd774c82a4ba09a76c631c55bbe6..9c3fb147f9414dd4dbfbc0194ce573f237511081 100644
--- a/src/tools/clangbackend/ipcsource/clangdocumentprocessor.h
+++ b/src/tools/clangbackend/ipcsource/clangdocumentprocessor.h
@@ -67,6 +67,7 @@ public:
 
 public: // for tests
     bool isSupportiveTranslationUnitInitialized() const;
+    JobRequests &queue();
     QList<Jobs::RunningJob> runningJobs() const;
     int queueSize() const;
 
diff --git a/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp b/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
index d6fc0ff659f8070eafcebf8c6db0a7bc8a49bd38..14de731eb62a8fec59ae76075c0bcfa75fd271ff 100644
--- a/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
+++ b/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp
@@ -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;
diff --git a/src/tools/clangbackend/ipcsource/clangjobqueue.cpp b/src/tools/clangbackend/ipcsource/clangjobqueue.cpp
index a6041ef97399b6bbceb2653d9bc0f84c45b80f5c..e76558051aff836be9997ecfcd55a21a63d2dc50 100644
--- a/src/tools/clangbackend/ipcsource/clangjobqueue.cpp
+++ b/src/tools/clangbackend/ipcsource/clangjobqueue.cpp
@@ -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;
 }
diff --git a/src/tools/clangbackend/ipcsource/clangjobqueue.h b/src/tools/clangbackend/ipcsource/clangjobqueue.h
index 82c46b5a1c26e7c3b4e315ce9080b7ee81cd660a..736ff3f2a3b3758d7e3550507a72ea72880c2953 100644
--- a/src/tools/clangbackend/ipcsource/clangjobqueue.h
+++ b/src/tools/clangbackend/ipcsource/clangjobqueue.h
@@ -52,7 +52,7 @@ public:
             const IsJobRunningForJobRequestHandler &isJobRunningHandler);
 
 public: // for tests
-    JobRequests queue() const;
+    JobRequests &queue();
     int size() const;
     void prioritizeRequests();
 
diff --git a/src/tools/clangbackend/ipcsource/clangjobrequest.cpp b/src/tools/clangbackend/ipcsource/clangjobrequest.cpp
index 90fe57da256a3b5d58050ba58cdb8cba9d780bda..bb9eb9bb993bd24ff13bdb138bf8066a6ffaac36 100644
--- a/src/tools/clangbackend/ipcsource/clangjobrequest.cpp
+++ b/src/tools/clangbackend/ipcsource/clangjobrequest.cpp
@@ -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
diff --git a/src/tools/clangbackend/ipcsource/clangjobrequest.h b/src/tools/clangbackend/ipcsource/clangjobrequest.h
index 83d8c3947ac5be9da8a0484a65062419f43bb8a1..a931514e854ff5b1da610f59cbd254f47c147072 100644
--- a/src/tools/clangbackend/ipcsource/clangjobrequest.h
+++ b/src/tools/clangbackend/ipcsource/clangjobrequest.h
@@ -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;
diff --git a/src/tools/clangbackend/ipcsource/clangjobs.cpp b/src/tools/clangbackend/ipcsource/clangjobs.cpp
index 424cc85f1db9e66348f84e5c3e91977e3e3d06e5..dfe619546cba0d0dad1c839089d7cf1c28fad7e9 100644
--- a/src/tools/clangbackend/ipcsource/clangjobs.cpp
+++ b/src/tools/clangbackend/ipcsource/clangjobs.cpp
@@ -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();
 }
diff --git a/src/tools/clangbackend/ipcsource/clangjobs.h b/src/tools/clangbackend/ipcsource/clangjobs.h
index 794577da910e643c93def819f83df359e97ccc69..c4167110f5e14bdd1ec21d8be412cbdc2a3a6f28 100644
--- a/src/tools/clangbackend/ipcsource/clangjobs.h
+++ b/src/tools/clangbackend/ipcsource/clangjobs.h
@@ -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;
 
diff --git a/src/tools/clangbackend/ipcsource/clangreferencescollector.cpp b/src/tools/clangbackend/ipcsource/clangreferencescollector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..695b30dc66a815500c08915f18eb2f45efbd0a8d
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangreferencescollector.cpp
@@ -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
diff --git a/src/tools/clangbackend/ipcsource/clangreferencescollector.h b/src/tools/clangbackend/ipcsource/clangreferencescollector.h
new file mode 100644
index 0000000000000000000000000000000000000000..1fa16967e642b6c5e403cffdb26096bb950dc60e
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangreferencescollector.h
@@ -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
+
diff --git a/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.cpp b/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f80072c0ed450ee18934463e0462e0089fc58cd8
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.cpp
@@ -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
diff --git a/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h b/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h
new file mode 100644
index 0000000000000000000000000000000000000000..179f8b845b8cc2afae9cf848dc30f6f27d2233fd
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h
@@ -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
diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
index f4d3390038fdfedce674bfbd7963149743bc558c..ca95c5f190b33a0088e906a61fdfa7389d2156a3 100644
--- a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
+++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp
@@ -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));
diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.h b/src/tools/clangbackend/ipcsource/clangtranslationunit.h
index 69574750923f47197589f75a260ef9daf0576524..5e6d28736a90e2a9123260ea463b4245b51c662d 100644
--- a/src/tools/clangbackend/ipcsource/clangtranslationunit.h
+++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.h
@@ -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;
diff --git a/src/tools/clangbackend/ipcsource/clangtype.cpp b/src/tools/clangbackend/ipcsource/clangtype.cpp
index 13ab8c9c6c0311460978531ac1940d308b1ce067..6b14b38dd847ddbceb701f80704270ca9696d6fa 100644
--- a/src/tools/clangbackend/ipcsource/clangtype.cpp
+++ b/src/tools/clangbackend/ipcsource/clangtype.cpp
@@ -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));
diff --git a/src/tools/clangbackend/ipcsource/clangtype.h b/src/tools/clangbackend/ipcsource/clangtype.h
index 6a51245ce6b432c7844825cbe280a401d2beaaaa..71ea1506ee56b5a5f6d34eb59bb548416947adea 100644
--- a/src/tools/clangbackend/ipcsource/clangtype.h
+++ b/src/tools/clangbackend/ipcsource/clangtype.h
@@ -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;
diff --git a/src/tools/clangbackend/ipcsource/cursor.cpp b/src/tools/clangbackend/ipcsource/cursor.cpp
index 1bc494ec71f10a6eb8c102a51cd88fc118ab4ac7..6367955fe4cda97b28154f06ec399b32448d2882 100644
--- a/src/tools/clangbackend/ipcsource/cursor.cpp
+++ b/src/tools/clangbackend/ipcsource/cursor.cpp
@@ -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);
diff --git a/src/tools/clangbackend/ipcsource/cursor.h b/src/tools/clangbackend/ipcsource/cursor.h
index 8b5e72df3d1b2b23710c38fcd3a1b8204f03333c..e1420f596dac2b2448cb82dc09948f71bb246597 100644
--- a/src/tools/clangbackend/ipcsource/cursor.h
+++ b/src/tools/clangbackend/ipcsource/cursor.h
@@ -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;
diff --git a/src/tools/clangbackend/ipcsource/sourcerange.cpp b/src/tools/clangbackend/ipcsource/sourcerange.cpp
index 62c52249d46e949ca32947f6fdeec32f0b49bbb1..86029cfd3ee751c9ba979fdb186f47d0e396ef47 100644
--- a/src/tools/clangbackend/ipcsource/sourcerange.cpp
+++ b/src/tools/clangbackend/ipcsource/sourcerange.cpp
@@ -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(),
diff --git a/src/tools/clangbackend/ipcsource/sourcerange.h b/src/tools/clangbackend/ipcsource/sourcerange.h
index df5612004e19390debc1a7e80cd142d29aa21977..955896ccfb0a2cce577bd05fab47e0397e158003 100644
--- a/src/tools/clangbackend/ipcsource/sourcerange.h
+++ b/src/tools/clangbackend/ipcsource/sourcerange.h
@@ -49,6 +49,8 @@ public:
     SourceLocation start() const;
     SourceLocation end() const;
 
+    bool contains(unsigned line, unsigned column) const;
+
     SourceRangeContainer toSourceRangeContainer() const;
 
     operator CXSourceRange() const;
diff --git a/tests/unit/echoserver/echoclangcodemodelserver.cpp b/tests/unit/echoserver/echoclangcodemodelserver.cpp
index d9495266269dcb68e4e7c8f5cb4cd12c518605a7..b9c465e1a70ec3cf52ab556b4601ed7fecd5ef5b 100644
--- a/tests/unit/echoserver/echoclangcodemodelserver.cpp
+++ b/tests/unit/echoserver/echoclangcodemodelserver.cpp
@@ -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);
diff --git a/tests/unit/echoserver/echoclangcodemodelserver.h b/tests/unit/echoserver/echoclangcodemodelserver.h
index c775dafc67f1c25c21de56c2d080f0d7bb0339fb..d381c0bdea07384909adcc17d9b06825aee5f8ce 100644
--- a/tests/unit/echoserver/echoclangcodemodelserver.h
+++ b/tests/unit/echoserver/echoclangcodemodelserver.h
@@ -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:
diff --git a/tests/unit/unittest/clangipcserver-test.cpp b/tests/unit/unittest/clangipcserver-test.cpp
index 4171b47cb70aae022d4d93398f3403b404d3ee23..d90c0d30fb227469b02e8e0ed35ace489e21b3f6 100644
--- a/tests/unit/unittest/clangipcserver-test.cpp
+++ b/tests/unit/unittest/clangipcserver-test.cpp
@@ -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 &currentEditor, 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;
diff --git a/tests/unit/unittest/clangjobqueue-test.cpp b/tests/unit/unittest/clangjobqueue-test.cpp
index a16e4c8719899a8ec53e032da2bb4fdbb7787a26..22af7aa01a7e0fa09254a6706b1ca95552759060 100644
--- a/tests/unit/unittest/clangjobqueue-test.cpp
+++ b/tests/unit/unittest/clangjobqueue-test.cpp
@@ -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)});
diff --git a/tests/unit/unittest/clangjobs-test.cpp b/tests/unit/unittest/clangjobs-test.cpp
index 427dab2e06f5397cc3b78790892e3de4b79f77f1..cf3507d1087fb20431753f2b6f2ad235291b0e17 100644
--- a/tests/unit/unittest/clangjobs-test.cpp
+++ b/tests/unit/unittest/clangjobs-test.cpp
@@ -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();
diff --git a/tests/unit/unittest/clangreferencescollector-test.cpp b/tests/unit/unittest/clangreferencescollector-test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4373450e3d5c2bb673026e1f41da3d62eb911e92
--- /dev/null
+++ b/tests/unit/unittest/clangreferencescollector-test.cpp
@@ -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
diff --git a/tests/unit/unittest/clangrequestreferencesjob-test.cpp b/tests/unit/unittest/clangrequestreferencesjob-test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..234d8258836c63fa7d24a1b1fcec54844441829d
--- /dev/null
+++ b/tests/unit/unittest/clangrequestreferencesjob-test.cpp
@@ -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
diff --git a/tests/unit/unittest/clientserverinprocess-test.cpp b/tests/unit/unittest/clientserverinprocess-test.cpp
index d4a1cab16dd972992db62a50d5984daff15f518d..92c3597c5ca31051da9c0dd2cadde74f5dc5388a 100644
--- a/tests/unit/unittest/clientserverinprocess-test.cpp
+++ b/tests/unit/unittest/clientserverinprocess-test.cpp
@@ -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>
diff --git a/tests/unit/unittest/data/references.cpp b/tests/unit/unittest/data/references.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d71a9e8f7981d76b23b64be3a6241d641262e70a
--- /dev/null
+++ b/tests/unit/unittest/data/references.cpp
@@ -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);
+}
diff --git a/tests/unit/unittest/dummyclangipcclient.h b/tests/unit/unittest/dummyclangipcclient.h
index c12bdcd832bde836891ba6bfbba8e079d337ed98..a9dca6ead60b5482270554e556449439dbea6504 100644
--- a/tests/unit/unittest/dummyclangipcclient.h
+++ b/tests/unit/unittest/dummyclangipcclient.h
@@ -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 {}
 };
diff --git a/tests/unit/unittest/mockclangcodemodelclient.h b/tests/unit/unittest/mockclangcodemodelclient.h
index 650980a9ab307edc316378e827f116e615da5046..a919de423e1ac2d6723bb93a762b80a3b9964e18 100644
--- a/tests/unit/unittest/mockclangcodemodelclient.h
+++ b/tests/unit/unittest/mockclangcodemodelclient.h
@@ -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));
 };
diff --git a/tests/unit/unittest/mockclangcodemodelserver.h b/tests/unit/unittest/mockclangcodemodelserver.h
index c2ef3cfd09a54b1885b8cb09b0ae6dcf6b384539..6285c48d2c2e7d3a15cbdf81b62d646f07d1c245 100644
--- a/tests/unit/unittest/mockclangcodemodelserver.h
+++ b/tests/unit/unittest/mockclangcodemodelserver.h
@@ -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));
 };
diff --git a/tests/unit/unittest/readandwritemessageblock-test.cpp b/tests/unit/unittest/readandwritemessageblock-test.cpp
index ace9effadb4c7b61a10532c17bba1f1248411709..4d6e663a87498518cf1bcda977effe36c313a949 100644
--- a/tests/unit/unittest/readandwritemessageblock-test.cpp
+++ b/tests/unit/unittest/readandwritemessageblock-test.cpp
@@ -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();
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 382df1df9046a690ffaf7d0f4107aaf834601e81..b5402ff3e0dd05d3fc9ad95fce359377f6517a3e 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -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 \