From bcd93b594eeac17ee5eebbf92a6ca78e7524674e Mon Sep 17 00:00:00 2001
From: Marco Bubke <marco.bubke@theqtcompany.com>
Date: Tue, 17 Nov 2015 13:33:31 +0100
Subject: [PATCH] Clang: Extract highlighting information

Prepare the move of the semantic highlighting to the clang back end. We
have it under tests too so it should be quite easy to make changes or
corrections.

Change-Id: I5706a8a06fde5a9ba2eba3a8ba62782102ac0bd3
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
---
 .../clangbackendipc/clangbackendipc_global.h  |  23 +
 src/libs/sqlite/utf8string.cpp                |   5 +
 src/libs/sqlite/utf8string.h                  |   1 +
 .../ipcsource/clangbackendclangipc-source.pri |  15 +-
 .../clangbackend/ipcsource/clangstring.cpp    |   7 +-
 .../clangbackend/ipcsource/clangstring.h      |   2 +
 src/tools/clangbackend/ipcsource/cursor.cpp   | 351 +++++++
 src/tools/clangbackend/ipcsource/cursor.h     | 129 +++
 .../ipcsource/highlightinginformation.cpp     | 304 ++++++
 .../ipcsource/highlightinginformation.h       |  86 ++
 .../ipcsource/highlightinginformations.cpp    |  79 ++
 .../ipcsource/highlightinginformations.h      |  74 ++
 .../highlightinginformationsiterator.h        |  99 ++
 .../ipcsource/skippedsourceranges.cpp         | 101 ++
 .../ipcsource/skippedsourceranges.h           |  63 ++
 .../clangbackend/ipcsource/sourcelocation.cpp |  38 +-
 .../clangbackend/ipcsource/sourcelocation.h   |  21 +-
 .../clangbackend/ipcsource/sourcerange.cpp    |  30 +
 .../clangbackend/ipcsource/sourcerange.h      |  11 +-
 .../ipcsource/translationunit.cpp             |  54 +-
 .../clangbackend/ipcsource/translationunit.h  |  18 +
 src/tools/clangbackend/ipcsource/type.cpp     | 157 +++
 src/tools/clangbackend/ipcsource/type.h       |  87 ++
 tests/unit/unittest/clangstringtest.cpp       |   9 +
 tests/unit/unittest/cursortest.cpp            | 819 ++++++++++++++++
 tests/unit/unittest/data/cursor.cpp           | 129 +++
 tests/unit/unittest/data/cursor.h             |  42 +
 .../data/highlightinginformations.cpp         | 385 ++++++++
 .../unittest/data/highlightinginformations.h  |   0
 .../unittest/data/skippedsourceranges.cpp     |  19 +
 .../unittest/highlightinginformationstest.cpp | 902 ++++++++++++++++++
 .../unit/unittest/skippedsourcerangestest.cpp | 159 +++
 tests/unit/unittest/sourcelocationtest.cpp    |  40 +-
 tests/unit/unittest/sourcerangetest.cpp       |  47 +-
 tests/unit/unittest/unittest.pro              |   5 +-
 35 files changed, 4292 insertions(+), 19 deletions(-)
 create mode 100644 src/tools/clangbackend/ipcsource/cursor.cpp
 create mode 100644 src/tools/clangbackend/ipcsource/cursor.h
 create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformation.cpp
 create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformation.h
 create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformations.cpp
 create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformations.h
 create mode 100644 src/tools/clangbackend/ipcsource/highlightinginformationsiterator.h
 create mode 100644 src/tools/clangbackend/ipcsource/skippedsourceranges.cpp
 create mode 100644 src/tools/clangbackend/ipcsource/skippedsourceranges.h
 create mode 100644 src/tools/clangbackend/ipcsource/type.cpp
 create mode 100644 src/tools/clangbackend/ipcsource/type.h
 create mode 100644 tests/unit/unittest/cursortest.cpp
 create mode 100644 tests/unit/unittest/data/cursor.cpp
 create mode 100644 tests/unit/unittest/data/cursor.h
 create mode 100644 tests/unit/unittest/data/highlightinginformations.cpp
 create mode 100644 tests/unit/unittest/data/highlightinginformations.h
 create mode 100644 tests/unit/unittest/data/skippedsourceranges.cpp
 create mode 100644 tests/unit/unittest/highlightinginformationstest.cpp
 create mode 100644 tests/unit/unittest/skippedsourcerangestest.cpp

diff --git a/src/libs/clangbackendipc/clangbackendipc_global.h b/src/libs/clangbackendipc/clangbackendipc_global.h
index 544a5b15ac..c9851069b5 100644
--- a/src/libs/clangbackendipc/clangbackendipc_global.h
+++ b/src/libs/clangbackendipc/clangbackendipc_global.h
@@ -53,5 +53,28 @@ enum class DiagnosticSeverity // one to one mapping of the clang enum numbers
     Error = 3,
     Fatal = 4
 };
+
+enum class HighlightingType
+{
+    Invalid,
+    Keyword,
+    StringLiteral,
+    NumberLiteral,
+    Comment,
+    Function,
+    VirtualFunction,
+    Type,
+    LocalVariable,
+    Field,
+    GlobalVariable,
+    Enumeration,
+    Operator,
+    Preprocessor,
+    PreprocessorDefinition,
+    PreprocessorExpansion,
+    Label,
+    OutputArgument
+};
+
 }
 #endif // CLANGBACKENDIPC_GLOBAL_H
diff --git a/src/libs/sqlite/utf8string.cpp b/src/libs/sqlite/utf8string.cpp
index b4492a9d19..c8cbaea223 100644
--- a/src/libs/sqlite/utf8string.cpp
+++ b/src/libs/sqlite/utf8string.cpp
@@ -158,6 +158,11 @@ bool Utf8String::endsWith(const Utf8String &text) const
     return byteArray.endsWith(text.byteArray);
 }
 
+bool Utf8String::isNull() const
+{
+    return byteArray.isNull();
+}
+
 bool Utf8String::isEmpty() const
 {
     return byteArray.isEmpty();
diff --git a/src/libs/sqlite/utf8string.h b/src/libs/sqlite/utf8string.h
index 52c6f46758..c6adfc9371 100644
--- a/src/libs/sqlite/utf8string.h
+++ b/src/libs/sqlite/utf8string.h
@@ -86,6 +86,7 @@ public:
     bool startsWith(const char *text) const;
     bool startsWith(char character) const;
     bool endsWith(const Utf8String &text) const;
+    bool isNull() const;
     bool isEmpty() const;
     bool hasContent() const;
 
diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
index 73aa363a95..93131082bf 100644
--- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
+++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri
@@ -25,7 +25,13 @@ HEADERS += $$PWD/clangipcserver.h \
     $$PWD/diagnosticsetiterator.h \
     $$PWD/clangfilesystemwatcher.h \
     $$PWD/translationunitalreadyexistsexception.h \
-    $$PWD/commandlinearguments.h
+    $$PWD/commandlinearguments.h \
+    $$PWD/cursor.h \
+    $$PWD/type.h \
+    $$PWD/highlightinginformations.h \
+    $$PWD/highlightinginformation.h \
+    $$PWD/highlightinginformationsiterator.h \
+    $$PWD/skippedsourceranges.h
 
 SOURCES += $$PWD/clangipcserver.cpp \
     $$PWD/codecompleter.cpp \
@@ -51,4 +57,9 @@ SOURCES += $$PWD/clangipcserver.cpp \
     $$PWD/fixit.cpp \
     $$PWD/clangfilesystemwatcher.cpp \
     $$PWD/translationunitalreadyexistsexception.cpp \
-    $$PWD/commandlinearguments.cpp
+    $$PWD/commandlinearguments.cpp \
+    $$PWD/cursor.cpp \
+    $$PWD/type.cpp \
+    $$PWD/highlightinginformations.cpp \
+    $$PWD/highlightinginformation.cpp \
+    $$PWD/skippedsourceranges.cpp
diff --git a/src/tools/clangbackend/ipcsource/clangstring.cpp b/src/tools/clangbackend/ipcsource/clangstring.cpp
index 200e834270..5decaf1549 100644
--- a/src/tools/clangbackend/ipcsource/clangstring.cpp
+++ b/src/tools/clangbackend/ipcsource/clangstring.cpp
@@ -61,6 +61,11 @@ ClangString &ClangString::operator=(ClangString &&other)
     return *this;
 }
 
+const char *ClangString::cString() const
+{
+    return clang_getCString(cxString);
+}
+
 ClangString::ClangString(ClangString &&other)
     : cxString(std::move(other.cxString))
 {
@@ -70,7 +75,7 @@ ClangString::ClangString(ClangString &&other)
 
 ClangString::operator Utf8String() const
 {
-    return Utf8String(clang_getCString(cxString), -1);
+    return Utf8String(cString(), -1);
 }
 
 } // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/clangstring.h b/src/tools/clangbackend/ipcsource/clangstring.h
index f18a612282..2db7b8ade0 100644
--- a/src/tools/clangbackend/ipcsource/clangstring.h
+++ b/src/tools/clangbackend/ipcsource/clangstring.h
@@ -51,6 +51,8 @@ public:
 
     operator Utf8String() const;
 
+    const char *cString() const;
+
     bool isNull() const;
 
 private:
diff --git a/src/tools/clangbackend/ipcsource/cursor.cpp b/src/tools/clangbackend/ipcsource/cursor.cpp
new file mode 100644
index 0000000000..7ea5009d4d
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/cursor.cpp
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "cursor.h"
+
+#include "clangstring.h"
+#include "sourcelocation.h"
+#include "sourcerange.h"
+
+#include <ostream>
+
+namespace ClangBackEnd {
+
+Cursor::Cursor()
+    : cxCursor(clang_getNullCursor())
+{
+}
+
+Cursor::Cursor(CXCursor cxCursor)
+    : cxCursor(cxCursor)
+{
+}
+
+bool Cursor::isNull() const
+{
+    return clang_Cursor_isNull(cxCursor);
+}
+
+bool Cursor::isValid() const
+{
+    return !clang_isInvalid(kind());
+}
+
+bool Cursor::isTranslationUnit() const
+{
+    return clang_isTranslationUnit(kind());
+}
+
+bool Cursor::isDefinition() const
+{
+    return clang_isCursorDefinition(cxCursor);
+}
+
+bool Cursor::isDynamicCall() const
+{
+    return clang_Cursor_isDynamicCall(cxCursor);
+}
+
+bool Cursor::isVirtualMethod() const
+{
+    return clang_CXXMethod_isVirtual(cxCursor);
+}
+
+bool Cursor::isPureVirtualMethod() const
+{
+    return clang_CXXMethod_isPureVirtual(cxCursor);
+}
+
+bool Cursor::isConstantMethod() const
+{
+    return clang_CXXMethod_isConst(cxCursor);
+}
+
+bool Cursor::isStaticMethod() const
+{
+    return clang_CXXMethod_isStatic(cxCursor);
+}
+
+bool Cursor::isCompoundType() const
+{
+    switch (kind()) {
+        case CXCursor_ClassDecl:
+        case CXCursor_StructDecl:
+        case CXCursor_UnionDecl: return true;
+        default: return false;
+    }
+}
+
+bool Cursor::isDeclaration() const
+{
+    return clang_isDeclaration(kind());
+}
+
+bool Cursor::isLocalVariable() const
+{
+    switch (semanticParent().kind()) {
+        case CXCursor_FunctionDecl:
+        case CXCursor_CXXMethod:
+        case CXCursor_Constructor:
+        case CXCursor_Destructor:
+        case CXCursor_ConversionFunction:
+        case CXCursor_FunctionTemplate:
+        case CXCursor_ObjCInstanceMethodDecl: return true;
+        default:
+            return false;
+    }
+}
+
+bool Cursor::hasFinalFunctionAttribute() const
+{
+    bool hasFinal = false;
+
+    visit([&] (Cursor cursor, Cursor /*parent*/) {
+        if (cursor.kind() == CXCursor_CXXFinalAttr) {
+            hasFinal = true;
+            return CXChildVisit_Break;
+        } else {
+            return CXChildVisit_Recurse;
+        }
+    });
+
+    return hasFinal;
+}
+
+bool Cursor::hasFinalClassAttribute() const
+{
+      bool hasFinal = false;
+
+      visit([&] (Cursor cursor, Cursor /*parent*/) {
+          switch (cursor.kind()) {
+              case CXCursor_CXXFinalAttr:
+                  hasFinal = true;
+                  return CXChildVisit_Break;
+              case CXCursor_CXXMethod:
+                  return CXChildVisit_Break;
+              default:
+                  return CXChildVisit_Recurse;
+          }
+      });
+
+      return hasFinal;
+}
+
+bool Cursor::isUnexposed() const
+{
+    return clang_isUnexposed(kind());
+}
+
+Utf8String Cursor::unifiedSymbolResolution() const
+{
+    return ClangString(clang_getCursorUSR(cxCursor));
+}
+
+Utf8String Cursor::mangling() const
+{
+    return ClangString(clang_Cursor_getMangling(cxCursor));
+}
+
+ClangString Cursor::spelling() const
+{
+    return ClangString(clang_getCursorSpelling(cxCursor));
+}
+
+Utf8String Cursor::displayName() const
+{
+    return ClangString(clang_getCursorDisplayName(cxCursor));
+}
+
+Utf8String Cursor::briefComment() const
+{
+    return ClangString(clang_Cursor_getBriefCommentText(cxCursor));
+}
+
+Utf8String Cursor::rawComment() const
+{
+    return ClangString(clang_Cursor_getRawCommentText(cxCursor));
+}
+
+int Cursor::argumentCount() const
+{
+    return clang_Cursor_getNumArguments(cxCursor);
+}
+
+Type Cursor::type() const
+{
+    return clang_getCursorType(cxCursor);
+}
+
+Type Cursor::nonPointerTupe() const
+{
+    auto typeResult = type();
+
+    if (typeResult.isPointer())
+        typeResult = typeResult.pointeeType();
+
+    return typeResult;
+}
+
+SourceLocation Cursor::sourceLocation() const
+{
+    return clang_getCursorLocation(cxCursor);
+}
+
+SourceRange Cursor::sourceRange() const
+{
+    return clang_getCursorExtent(cxCursor);
+}
+
+SourceRange Cursor::commentRange() const
+{
+    return clang_Cursor_getCommentRange(cxCursor);
+}
+
+Cursor Cursor::definition() const
+{
+    return clang_getCursorDefinition(cxCursor);
+}
+
+Cursor Cursor::canonical() const
+{
+    return clang_getCanonicalCursor(cxCursor);
+}
+
+Cursor Cursor::referenced() const
+{
+    return clang_getCursorReferenced(cxCursor);
+}
+
+Cursor Cursor::semanticParent() const
+{
+    return clang_getCursorSemanticParent(cxCursor);
+}
+
+Cursor Cursor::lexicalParent() const
+{
+    return clang_getCursorLexicalParent(cxCursor);
+}
+
+Cursor Cursor::functionBaseDeclaration() const
+{
+    auto functionBaseCursor = functionBase();
+
+    if (functionBaseCursor.isValid())
+        return functionBaseCursor.nonPointerTupe().canonical().declaration();
+    else
+        return semanticParent().semanticParent();
+}
+
+Cursor Cursor::functionBase() const
+{
+    Cursor functionBaseCursor;
+
+    visit([&] (Cursor cursor, Cursor /*parentCursor*/) {
+        switch (cursor.kind()) {
+            case CXCursor_DeclRefExpr:
+                functionBaseCursor = cursor;                                                       ;
+                return CXChildVisit_Break;
+            default:
+                 return CXChildVisit_Recurse;
+        }
+    });
+
+    return functionBaseCursor;
+}
+
+Cursor Cursor::argument(int index) const
+{
+    return clang_Cursor_getArgument(cxCursor, index);
+}
+namespace {
+void collectOutputArguments(const Cursor &callExpression,
+                            std::vector<Cursor> &outputArguments)
+{
+    auto callExpressionType = callExpression.referenced().type();
+    auto argumentCount = callExpression.argumentCount();
+    outputArguments.reserve(argumentCount);
+
+    for (int argumentIndex = 0; argumentIndex < argumentCount; ++argumentIndex) {
+        auto argument = callExpression.argument(argumentIndex);
+        auto argumentType = callExpressionType.argument(argumentIndex);
+
+        if (!argument.isUnexposed() && argumentType.isOutputParameter())
+            outputArguments.push_back(callExpression.argument(argumentIndex));
+    }
+}
+}
+
+std::vector<Cursor> Cursor::outputArguments() const
+{
+    std::vector<Cursor> outputArguments;
+
+    if (kind() == CXCursor_CallExpr)
+        collectOutputArguments(*this, outputArguments);
+
+    return outputArguments;
+}
+
+CXCursorKind Cursor::kind() const
+{
+    return clang_getCursorKind(cxCursor);
+}
+
+bool operator==(const Cursor &first, const Cursor &second)
+{
+    return clang_equalCursors(first.cxCursor, second.cxCursor);
+}
+
+void PrintTo(CXCursorKind cursorKind, ::std::ostream *os)
+{
+    ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursorKind));
+    *os << cursorKindSpelling.cString();
+}
+
+void PrintTo(const Cursor &cursor, ::std::ostream*os)
+{
+    if (cursor.isValid()) {
+        ClangString cursorKindSpelling(clang_getCursorKindSpelling(cursor.kind()));
+        *os << cursorKindSpelling.cString() << " ";
+
+        auto identifier = cursor.displayName();
+        if (identifier.hasContent()) {
+            *os  << "\""
+                 << identifier.constData()
+                 << "\": ";
+        }
+
+        PrintTo(cursor.sourceLocation(), os);
+    } else {
+        *os << "Invalid cursor!";
+    }
+}
+
+} // namespace ClangBackEnd
+
diff --git a/src/tools/clangbackend/ipcsource/cursor.h b/src/tools/clangbackend/ipcsource/cursor.h
new file mode 100644
index 0000000000..d4256401e5
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/cursor.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CLANGBACKEND_CURSOR_H
+#define CLANGBACKEND_CURSOR_H
+
+#include "type.h"
+
+#include <clang-c/Index.h>
+
+#include <iosfwd>
+
+#include <vector>
+
+class Utf8String;
+
+namespace ClangBackEnd {
+
+class SourceLocation;
+class SourceRange;
+class ClangString;
+
+class Cursor
+{
+    friend class Type;
+    friend bool operator==(const Cursor &first, const Cursor &second);
+public:
+    Cursor();
+    Cursor(CXCursor cxCursor);
+
+    bool isNull() const;
+    bool isValid() const;
+
+    bool isTranslationUnit() const;
+    bool isDefinition() const;
+    bool isDynamicCall() const;
+    bool isVirtualMethod() const;
+    bool isPureVirtualMethod() const;
+    bool isConstantMethod() const;
+    bool isStaticMethod() const;
+    bool isCompoundType() const;
+    bool isDeclaration() const;
+    bool isLocalVariable() const;
+    bool hasFinalFunctionAttribute() const;
+    bool hasFinalClassAttribute() const;
+    bool isUnexposed() const;
+
+    Utf8String unifiedSymbolResolution() const;
+    Utf8String mangling() const;
+    ClangString spelling() const;
+    Utf8String displayName() const;
+    Utf8String briefComment() const;
+    Utf8String rawComment() const;
+    int argumentCount() const;
+
+    Type type() const;
+    Type nonPointerTupe() const;
+
+    SourceLocation sourceLocation() const;
+    SourceRange sourceRange() const;
+    SourceRange commentRange() const;
+
+    Cursor definition() const;
+    Cursor canonical() const;
+    Cursor alias() const;
+    Cursor referenced() const;
+    Cursor semanticParent() const;
+    Cursor lexicalParent() const;
+    Cursor functionBaseDeclaration() const;
+    Cursor functionBase() const;
+    Cursor argument(int index) const;
+    std::vector<Cursor> outputArguments() const;
+
+    CXCursorKind kind() const;
+
+    template <class VisitorCallback>
+    void visit(VisitorCallback visitorCallback) const;
+
+private:
+    CXCursor cxCursor;
+};
+
+template <class VisitorCallback>
+void Cursor::visit(VisitorCallback visitorCallback) const
+{
+    auto visitor = [] (CXCursor cursor, CXCursor parent, CXClientData lambda) -> CXChildVisitResult {
+        auto &visitorCallback = *static_cast<VisitorCallback*>(lambda);
+
+        return visitorCallback(cursor, parent);
+    };
+
+    clang_visitChildren(cxCursor, visitor, &visitorCallback);
+}
+
+bool operator==(const Cursor &first, const Cursor &second);
+
+void PrintTo(CXCursorKind cursorKind, ::std::ostream *os);
+void PrintTo(const Cursor &cursor, ::std::ostream* os);
+} // namespace ClangBackEnd
+
+
+#endif // CLANGBACKEND_CURSOR_H
diff --git a/src/tools/clangbackend/ipcsource/highlightinginformation.cpp b/src/tools/clangbackend/ipcsource/highlightinginformation.cpp
new file mode 100644
index 0000000000..808a0407d1
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/highlightinginformation.cpp
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "clangstring.h"
+#include "cursor.h"
+#include "highlightinginformation.h"
+#include "sourcelocation.h"
+#include "sourcerange.h"
+
+#include <cstring>
+#include <ostream>
+
+#include <QDebug>
+
+namespace ClangBackEnd {
+
+HighlightingInformation::HighlightingInformation(const CXCursor &cxCursor,
+                                                 CXToken *cxToken,
+                                                 CXTranslationUnit cxTranslationUnit)
+{
+    const SourceRange sourceRange = clang_getTokenExtent(cxTranslationUnit, *cxToken);
+    const auto start = sourceRange.start();
+    const auto end = sourceRange.end();
+
+    originalCursor = cxCursor;
+    line = start.line();
+    column = start.column();
+    length = end.offset() - start.offset();
+    type = kind(cxToken, originalCursor);
+}
+
+HighlightingInformation::HighlightingInformation(uint line, uint column, uint length, HighlightingType type)
+    : line(line),
+      column(column),
+      length(length),
+      type(type)
+{
+}
+
+bool HighlightingInformation::hasType(HighlightingType type) const
+{
+    return this->type == type;
+}
+
+bool HighlightingInformation::hasFunctionArguments() const
+{
+    return originalCursor.argumentCount() > 0;
+}
+
+QVector<HighlightingInformation> HighlightingInformation::outputFunctionArguments() const
+{
+    QVector<HighlightingInformation> outputFunctionArguments;
+
+    return outputFunctionArguments;
+}
+
+namespace {
+
+bool isFinalFunction(const Cursor &cursor)
+{
+    auto referencedCursor = cursor.referenced();
+    if (referencedCursor.hasFinalFunctionAttribute())
+        return true;
+
+    else return false;
+}
+
+bool isFunctionInFinalClass(const Cursor &cursor)
+{
+    auto functionBase = cursor.functionBaseDeclaration();
+    if (functionBase.isValid() && functionBase.hasFinalClassAttribute())
+        return true;
+
+    return false;
+}
+}
+
+HighlightingType HighlightingInformation::memberReferenceKind(const Cursor &cursor) const
+{
+    if (cursor.isDynamicCall()) {
+        if (isFinalFunction(cursor) || isFunctionInFinalClass(cursor))
+            return HighlightingType::Function;
+        else
+            return HighlightingType::VirtualFunction;
+    }
+
+    return identifierKind(cursor.referenced());
+
+}
+
+HighlightingType HighlightingInformation::referencedTypeKind(const Cursor &cursor) const
+{
+    const Cursor referencedCursor = cursor.referenced();
+
+    switch (referencedCursor.kind()) {
+        case CXCursor_ClassDecl:
+        case CXCursor_StructDecl:
+        case CXCursor_UnionDecl:
+        case CXCursor_TemplateTypeParameter:
+        case CXCursor_TypeAliasDecl:         return HighlightingType::Type;
+        case CXCursor_EnumDecl:              return HighlightingType::Enumeration;
+        default:                             return HighlightingType::Invalid;
+    }
+
+    Q_UNREACHABLE();
+}
+
+HighlightingType HighlightingInformation::variableKind(const Cursor &cursor) const
+{
+    if (cursor.isLocalVariable())
+        return HighlightingType::LocalVariable;
+    else
+        return HighlightingType::GlobalVariable;
+}
+
+bool HighlightingInformation::isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const
+{
+    return cursor.isVirtualMethod()
+        && (originalCursor.isDeclaration() || originalCursor.isDefinition());
+}
+namespace {
+bool isNotFinalFunction(const Cursor &cursor)
+{
+    return !cursor.hasFinalFunctionAttribute();
+}
+
+}
+bool HighlightingInformation::isRealDynamicCall(const Cursor &cursor) const
+{
+
+    return originalCursor.isDynamicCall() && isNotFinalFunction(cursor);
+}
+
+HighlightingType HighlightingInformation::functionKind(const Cursor &cursor) const
+{
+    if (isRealDynamicCall(cursor) || isVirtualMethodDeclarationOrDefinition(cursor))
+        return HighlightingType::VirtualFunction;
+    else
+        return HighlightingType::Function;
+}
+
+HighlightingType HighlightingInformation::identifierKind(const Cursor &cursor) const
+{
+    switch (cursor.kind()) {
+        case CXCursor_Destructor:
+        case CXCursor_Constructor:
+        case CXCursor_FunctionDecl:
+        case CXCursor_CallExpr:
+        case CXCursor_CXXMethod:                 return functionKind(cursor);
+        case CXCursor_NonTypeTemplateParameter:
+        case CXCursor_ParmDecl:                  return HighlightingType::LocalVariable;
+        case CXCursor_VarDecl:                   return variableKind(cursor);
+        case CXCursor_DeclRefExpr:               return identifierKind(cursor.referenced());
+        case CXCursor_MemberRefExpr:             return memberReferenceKind(cursor);
+        case CXCursor_FieldDecl:
+        case CXCursor_MemberRef:
+        case CXCursor_ObjCIvarDecl:
+        case CXCursor_ObjCPropertyDecl:
+        case CXCursor_ObjCClassMethodDecl:
+        case CXCursor_ObjCInstanceMethodDecl:
+        case CXCursor_ObjCSynthesizeDecl:
+        case CXCursor_ObjCDynamicDecl:           return HighlightingType::Field;
+        case CXCursor_TypeRef:                   return referencedTypeKind(cursor);
+        case CXCursor_ClassDecl:
+        case CXCursor_TemplateTypeParameter:
+        case CXCursor_TemplateTemplateParameter:
+        case CXCursor_UnionDecl:
+        case CXCursor_StructDecl:
+        case CXCursor_TemplateRef:
+        case CXCursor_Namespace:
+        case CXCursor_NamespaceRef:
+        case CXCursor_NamespaceAlias:
+        case CXCursor_TypeAliasDecl:
+        case CXCursor_ClassTemplate:
+        case CXCursor_UnexposedDecl:
+        case CXCursor_CXXStaticCastExpr:
+        case CXCursor_CXXReinterpretCastExpr:
+        case CXCursor_ObjCCategoryDecl:
+        case CXCursor_ObjCCategoryImplDecl:
+        case CXCursor_ObjCImplementationDecl:
+        case CXCursor_ObjCInterfaceDecl:
+        case CXCursor_ObjCProtocolDecl:
+        case CXCursor_ObjCProtocolRef:
+        case CXCursor_ObjCClassRef:
+        case CXCursor_ObjCSuperClassRef:         return HighlightingType::Type;
+        case CXCursor_FunctionTemplate:          return HighlightingType::Function;
+        case CXCursor_EnumConstantDecl:          return HighlightingType::Enumeration;
+        case CXCursor_EnumDecl:                  return referencedTypeKind(cursor);
+        case CXCursor_PreprocessingDirective:    return HighlightingType::Preprocessor;
+        case CXCursor_MacroExpansion:            return HighlightingType::PreprocessorExpansion;
+        case CXCursor_MacroDefinition:           return HighlightingType::PreprocessorDefinition;
+        case CXCursor_InclusionDirective:        return HighlightingType::StringLiteral;
+        case CXCursor_LabelRef:
+        case CXCursor_LabelStmt:                 return HighlightingType::Label;
+        default:                                 return HighlightingType::Invalid;
+    }
+
+    Q_UNREACHABLE();
+}
+
+namespace {
+HighlightingType literalKind(const Cursor &cursor)
+{
+    switch (cursor.kind()) {
+        case CXCursor_CharacterLiteral:
+        case CXCursor_StringLiteral:
+        case CXCursor_ObjCStringLiteral: return HighlightingType::StringLiteral;
+        case CXCursor_IntegerLiteral:
+        case CXCursor_ImaginaryLiteral:
+        case CXCursor_FloatingLiteral:   return HighlightingType::NumberLiteral;
+        default:                         return HighlightingType::Invalid;
+    }
+
+    Q_UNREACHABLE();
+}
+
+
+HighlightingType punctationKind(const Cursor &cursor)
+{
+    switch (cursor.kind()) {
+        case CXCursor_DeclRefExpr: return HighlightingType::Operator;
+        default:                   return HighlightingType::Invalid;
+    }
+}
+
+}
+HighlightingType HighlightingInformation::kind(CXToken *cxToken, const Cursor &cursor) const
+{
+    auto cxTokenKind = clang_getTokenKind(*cxToken);
+
+    switch (cxTokenKind) {
+        case CXToken_Keyword:     return HighlightingType::Keyword;
+        case CXToken_Punctuation: return punctationKind(cursor);
+        case CXToken_Identifier:  return identifierKind(cursor);
+        case CXToken_Comment:     return HighlightingType::Comment;
+        case CXToken_Literal:     return literalKind(cursor);
+    }
+
+    Q_UNREACHABLE();
+}
+
+void PrintTo(const HighlightingInformation& information, ::std::ostream *os)
+{
+    *os << "type: ";
+    PrintTo(information.type, os);
+    *os << " line: " << information.line
+        << " column: " << information.column
+        << " length: " << information.length;
+}
+
+void PrintTo(HighlightingType highlightingType, std::ostream *os)
+{
+    switch (highlightingType) {
+        case HighlightingType::Invalid: *os << "Invalid"; break;
+        case HighlightingType::Comment: *os << "Comment"; break;
+        case HighlightingType::Keyword: *os << "Keyword"; break;
+        case HighlightingType::StringLiteral: *os << "StringLiteral"; break;
+        case HighlightingType::NumberLiteral: *os << "NumberLiteral"; break;
+        case HighlightingType::Function: *os << "Function"; break;
+        case HighlightingType::VirtualFunction: *os << "VirtualFunction"; break;
+        case HighlightingType::Type: *os << "Type"; break;
+        case HighlightingType::LocalVariable: *os << "LocalVariable"; break;
+        case HighlightingType::GlobalVariable: *os << "GlobalVariable"; break;
+        case HighlightingType::Field: *os << "Field"; break;
+        case HighlightingType::Enumeration: *os << "Enumeration"; break;
+        case HighlightingType::Operator: *os << "Operator"; break;
+        case HighlightingType::Preprocessor: *os << "Preprocessor"; break;
+        case HighlightingType::Label: *os << "Label"; break;
+        case HighlightingType::OutputArgument: *os << "OutputArgument"; break;
+        case HighlightingType::PreprocessorDefinition: *os << "PreprocessorDefinition"; break;
+        case HighlightingType::PreprocessorExpansion: *os << "PreprocessorExpansion"; break;
+    }
+}
+
+
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/highlightinginformation.h b/src/tools/clangbackend/ipcsource/highlightinginformation.h
new file mode 100644
index 0000000000..ee327b6213
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/highlightinginformation.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CLANGBACKEND_HIGHLIGHTINGINFORMATION_H
+#define CLANGBACKEND_HIGHLIGHTINGINFORMATION_H
+
+#include <clangbackendipc_global.h>
+
+#include "cursor.h"
+
+#include <clang-c/Index.h>
+
+namespace ClangBackEnd {
+
+class HighlightingInformation
+{
+    friend bool operator==(const HighlightingInformation &first, const HighlightingInformation &second);
+    friend void PrintTo(const HighlightingInformation& highlightingInformation, ::std::ostream *os);
+
+public:
+    HighlightingInformation(const CXCursor &cxCursor, CXToken *cxToken, CXTranslationUnit cxTranslationUnit);
+    HighlightingInformation(uint line, uint column, uint length, HighlightingType type);
+
+    bool hasType(HighlightingType type) const;
+    bool hasFunctionArguments() const;
+    QVector<HighlightingInformation> outputFunctionArguments() const;
+
+private:
+    HighlightingType identifierKind(const Cursor &cursor) const;
+    HighlightingType referencedTypeKind(const Cursor &cursor) const;
+    HighlightingType variableKind(const Cursor &cursor) const;
+    bool isVirtualMethodDeclarationOrDefinition(const Cursor &cursor) const;
+    HighlightingType functionKind(const Cursor &cursor) const;
+    HighlightingType memberReferenceKind(const Cursor &cursor) const;
+    HighlightingType kind(CXToken *cxToken, const Cursor &cursor) const;
+    bool isRealDynamicCall(const Cursor &cursor) const;
+
+private:
+    Cursor originalCursor;
+    uint line;
+    uint column;
+    uint length;
+    HighlightingType type;
+};
+
+void PrintTo(const HighlightingInformation& highlightingInformation, ::std::ostream *os);
+void PrintTo(HighlightingType highlightingType, ::std::ostream *os);
+
+inline bool operator==(const HighlightingInformation &first, const HighlightingInformation &second)
+{
+    return first.line == second.line
+        && first.column == second.column
+        && first.length == second.length
+        && first.type == second.type;
+}
+
+} // namespace ClangBackEnd
+
+#endif // CLANGBACKEND_HIGHLIGHTINGINFORMATION_H
diff --git a/src/tools/clangbackend/ipcsource/highlightinginformations.cpp b/src/tools/clangbackend/ipcsource/highlightinginformations.cpp
new file mode 100644
index 0000000000..f7157768fd
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/highlightinginformations.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "highlightinginformations.h"
+
+namespace ClangBackEnd {
+
+HighlightingInformations::HighlightingInformations(CXTranslationUnit cxTranslationUnit, CXToken *tokens, uint tokensCount)
+    : cxTranslationUnit(cxTranslationUnit),
+      cxToken(tokens),
+      cxTokenCount(tokensCount)
+{
+    cxCursor.resize(tokensCount);
+    clang_annotateTokens(cxTranslationUnit, cxToken, cxTokenCount, cxCursor.data());
+}
+
+HighlightingInformations::~HighlightingInformations()
+{
+    clang_disposeTokens(cxTranslationUnit, cxToken, cxTokenCount);
+}
+
+HighlightingInformations::const_iterator HighlightingInformations::begin() const
+{
+    return const_iterator(cxCursor.cbegin(), cxToken, cxTranslationUnit);
+}
+
+HighlightingInformations::const_iterator HighlightingInformations::end() const
+{
+    return const_iterator(cxCursor.cend(), cxToken + cxTokenCount, cxTranslationUnit);
+}
+
+bool HighlightingInformations::isEmpty() const
+{
+    return cxTokenCount == 0;
+}
+
+bool ClangBackEnd::HighlightingInformations::isNull() const
+{
+    return cxToken == nullptr;
+}
+
+uint HighlightingInformations::size() const
+{
+    return cxTokenCount;
+}
+
+HighlightingInformation HighlightingInformations::operator[](size_t index) const
+{
+    return HighlightingInformation(cxCursor[index], cxToken + index, cxTranslationUnit);
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/highlightinginformations.h b/src/tools/clangbackend/ipcsource/highlightinginformations.h
new file mode 100644
index 0000000000..2c7b8ce9bb
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/highlightinginformations.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CLANGBACKEND_HIGHLIGHTINGINFORMATIONS_H
+#define CLANGBACKEND_HIGHLIGHTINGINFORMATIONS_H
+
+#include "highlightinginformationsiterator.h"
+
+#include <clang-c/Index.h>
+
+#include <vector>
+
+namespace ClangBackEnd {
+
+using uint = unsigned int;
+
+class HighlightingInformations
+{
+public:
+    using const_iterator = HighlightingInformationsIterator;
+    using value_type = HighlightingInformation;
+
+public:
+    HighlightingInformations() = default;
+    HighlightingInformations(CXTranslationUnit cxTranslationUnit, CXToken *tokens, uint tokensCount);
+    ~HighlightingInformations();
+
+    bool isEmpty() const;
+    bool isNull() const;
+    uint size() const;
+
+    HighlightingInformation operator[](size_t index) const;
+
+    const_iterator begin() const;
+    const_iterator end() const;
+
+private:
+    CXTranslationUnit cxTranslationUnit = nullptr;
+    CXToken *const cxToken = nullptr;
+    const uint cxTokenCount = 0;
+
+    std::vector<CXCursor> cxCursor;
+};
+
+} // namespace ClangBackEnd
+
+#endif // CLANGBACKEND_HIGHLIGHTINGINFORMATIONS_H
diff --git a/src/tools/clangbackend/ipcsource/highlightinginformationsiterator.h b/src/tools/clangbackend/ipcsource/highlightinginformationsiterator.h
new file mode 100644
index 0000000000..53f540970e
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/highlightinginformationsiterator.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef HIGHLIGHTINGINFORMATIONSITERATOR_H
+#define HIGHLIGHTINGINFORMATIONSITERATOR_H
+
+#include "highlightinginformation.h"
+
+#include <iterator>
+#include <vector>
+
+#include <clang-c/Index.h>
+
+namespace ClangBackEnd {
+
+using uint = unsigned int;
+
+class DiagnosticSet;
+class Diagnostic;
+
+class HighlightingInformationsIterator : public std::iterator<std::forward_iterator_tag, HighlightingInformation, uint>
+{
+public:
+    HighlightingInformationsIterator(std::vector<CXCursor>::const_iterator cxCursorIterator,
+                                     CXToken *cxToken,
+                                     CXTranslationUnit cxTranslationUnit)
+        : cxCursorIterator(cxCursorIterator),
+          cxToken(cxToken),
+          cxTranslationUnit(cxTranslationUnit)
+    {}
+
+    HighlightingInformationsIterator(const HighlightingInformationsIterator &other)
+        : cxCursorIterator(other.cxCursorIterator)
+    {}
+
+    HighlightingInformationsIterator& operator++()
+    {
+        ++cxCursorIterator;
+        ++cxToken;
+
+        return *this;
+    }
+
+    HighlightingInformationsIterator operator++(int)
+    {
+        return HighlightingInformationsIterator(cxCursorIterator++, cxToken++, cxTranslationUnit);
+    }
+
+    bool operator==(HighlightingInformationsIterator other) const
+    {
+        return cxCursorIterator == other.cxCursorIterator;
+    }
+
+    bool operator!=(HighlightingInformationsIterator other) const
+    {
+        return cxCursorIterator != other.cxCursorIterator;
+    }
+
+    HighlightingInformation operator*()
+    {
+        return HighlightingInformation(*cxCursorIterator, cxToken, cxTranslationUnit);
+    }
+
+private:
+    std::vector<CXCursor>::const_iterator cxCursorIterator;
+    CXToken *cxToken;
+    CXTranslationUnit cxTranslationUnit;
+};
+
+} // namespace ClangBackEnd
+
+#endif // HIGHLIGHTINGINFORMATIONSITERATOR_H
diff --git a/src/tools/clangbackend/ipcsource/skippedsourceranges.cpp b/src/tools/clangbackend/ipcsource/skippedsourceranges.cpp
new file mode 100644
index 0000000000..2a39131474
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/skippedsourceranges.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+#include "skippedsourceranges.h"
+
+#include "sourcerangecontainer.h"
+
+#include <QVector>
+
+#include <algorithm>
+
+namespace ClangBackEnd {
+
+SkippedSourceRanges::SkippedSourceRanges(CXTranslationUnit cxTranslationUnit, const char *filePath)
+{
+    cxSkippedSourceRanges = clang_getSkippedRanges(cxTranslationUnit,
+                                                   clang_getFile(cxTranslationUnit,
+                                                                 filePath));
+}
+
+SkippedSourceRanges::~SkippedSourceRanges()
+{
+    clang_disposeSourceRangeList(cxSkippedSourceRanges);
+}
+
+SkippedSourceRanges &SkippedSourceRanges::operator=(SkippedSourceRanges &&other)
+{
+    if (this != &other) {
+        cxSkippedSourceRanges = other.cxSkippedSourceRanges;
+        other.cxSkippedSourceRanges = nullptr;
+    }
+
+    return *this;
+}
+
+std::vector<SourceRange> SkippedSourceRanges::sourceRanges() const
+{
+    std::vector<SourceRange> sourceRanges;
+
+    auto sourceRangeCount = cxSkippedSourceRanges->count;
+    sourceRanges.reserve(sourceRangeCount);
+
+    std::copy(cxSkippedSourceRanges->ranges,
+              cxSkippedSourceRanges->ranges + sourceRangeCount,
+              std::back_inserter(sourceRanges));
+
+    return sourceRanges;
+}
+
+QVector<SourceRangeContainer> SkippedSourceRanges::toSourceRangeContainers() const
+{
+    QVector<SourceRangeContainer> sourceRangeContainers;
+
+    auto sourceRanges = this->sourceRanges();
+
+    std::copy(sourceRanges.cbegin(),
+              sourceRanges.cend(),
+              std::back_inserter(sourceRangeContainers));
+
+    return sourceRangeContainers;
+}
+
+ClangBackEnd::SkippedSourceRanges::operator QVector<SourceRangeContainer>() const
+{
+    return toSourceRangeContainers();
+}
+
+SkippedSourceRanges::SkippedSourceRanges(SkippedSourceRanges &&other)
+    : cxSkippedSourceRanges(other.cxSkippedSourceRanges)
+{
+    other.cxSkippedSourceRanges = nullptr;
+}
+
+} // namespace ClangBackEnd
+
diff --git a/src/tools/clangbackend/ipcsource/skippedsourceranges.h b/src/tools/clangbackend/ipcsource/skippedsourceranges.h
new file mode 100644
index 0000000000..8d38bc50c9
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/skippedsourceranges.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+#ifndef CLANGBACKEND_SKIPPEDSOURCERANGES_H
+#define CLANGBACKEND_SKIPPEDSOURCERANGES_H
+
+#include "sourcerange.h"
+
+namespace ClangBackEnd {
+
+class SourceRangeContainer;
+
+class SkippedSourceRanges
+{
+public:
+    SkippedSourceRanges(CXTranslationUnit TranslationUnit, const char *filePath);
+    ~SkippedSourceRanges();
+
+    SkippedSourceRanges(const SkippedSourceRanges &) = delete;
+    const SkippedSourceRanges &operator=(const SkippedSourceRanges &) = delete;
+
+    SkippedSourceRanges(SkippedSourceRanges &&);
+    SkippedSourceRanges &operator=(SkippedSourceRanges &&);
+
+    std::vector<SourceRange> sourceRanges() const;
+
+    QVector<SourceRangeContainer> toSourceRangeContainers() const;
+
+    operator QVector<SourceRangeContainer>() const;
+
+private:
+    CXSourceRangeList *cxSkippedSourceRanges;
+};
+
+} // namespace ClangBackEnd
+
+#endif // CLANGBACKEND_SKIPPEDSOURCERANGES_H
diff --git a/src/tools/clangbackend/ipcsource/sourcelocation.cpp b/src/tools/clangbackend/ipcsource/sourcelocation.cpp
index 8a7cd0d871..e04f44c7d8 100644
--- a/src/tools/clangbackend/ipcsource/sourcelocation.cpp
+++ b/src/tools/clangbackend/ipcsource/sourcelocation.cpp
@@ -31,6 +31,7 @@
 #include "sourcelocation.h"
 
 #include "clangstring.h"
+#include "translationunit.h"
 
 #include <utf8string.h>
 
@@ -39,6 +40,11 @@
 
 namespace ClangBackEnd {
 
+SourceLocation::SourceLocation()
+    : cxSourceLocation(clang_getNullLocation())
+{
+}
+
 const Utf8String &SourceLocation::filePath() const
 {
     return filePath_;
@@ -65,6 +71,7 @@ SourceLocationContainer SourceLocation::toSourceLocationContainer() const
 }
 
 SourceLocation::SourceLocation(CXSourceLocation cxSourceLocation)
+    : cxSourceLocation(cxSourceLocation)
 {
     CXFile cxFile;
 
@@ -77,10 +84,37 @@ SourceLocation::SourceLocation(CXSourceLocation cxSourceLocation)
     filePath_ = ClangString(clang_getFileName(cxFile));
 }
 
+SourceLocation::SourceLocation(CXTranslationUnit cxTranslationUnit,
+                               const Utf8String &filePath,
+                               uint line,
+                               uint column)
+    : cxSourceLocation(clang_getLocation(cxTranslationUnit,
+                                         clang_getFile(cxTranslationUnit,
+                                                       filePath.constData()),
+                                         line,
+                                         column)),
+      filePath_(filePath),
+      line_(line)
+{
+}
+
+bool operator==(const SourceLocation &first, const SourceLocation &second)
+{
+    return clang_equalLocations(first.cxSourceLocation, second.cxSourceLocation);
+}
+
+SourceLocation::operator CXSourceLocation() const
+{
+    return cxSourceLocation;
+}
+
 void PrintTo(const SourceLocation &sourceLocation, std::ostream *os)
 {
-    *os << sourceLocation.filePath().constData()
-        << ", line: " << sourceLocation.line()
+    auto filePath = sourceLocation.filePath();
+    if (filePath.hasContent())
+        *os << filePath.constData()  << ", ";
+
+    *os << "line: " << sourceLocation.line()
         << ", column: "<< sourceLocation.column()
         << ", offset: "<< sourceLocation.offset();
 }
diff --git a/src/tools/clangbackend/ipcsource/sourcelocation.h b/src/tools/clangbackend/ipcsource/sourcelocation.h
index 3ee500623b..83ba6c77c9 100644
--- a/src/tools/clangbackend/ipcsource/sourcelocation.h
+++ b/src/tools/clangbackend/ipcsource/sourcelocation.h
@@ -38,13 +38,19 @@
 namespace ClangBackEnd {
 
 class SourceLocationContainer;
+class TranslationUnit;
 
 class SourceLocation
 {
     friend class Diagnostic;
     friend class SourceRange;
+    friend class TranslationUnit;
+    friend class Cursor;
+    friend bool operator==(const SourceLocation &first, const SourceLocation &second);
 
 public:
+    SourceLocation();
+
     const Utf8String &filePath() const;
     uint line() const;
     uint column() const;
@@ -54,14 +60,23 @@ public:
 
 private:
     SourceLocation(CXSourceLocation cxSourceLocation);
+    SourceLocation(CXTranslationUnit cxTranslationUnit,
+                   const Utf8String &filePath,
+                   uint line,
+                   uint column);
+
+    operator CXSourceLocation() const;
 
 private:
+   CXSourceLocation cxSourceLocation;
    Utf8String filePath_;
-   uint line_;
-   uint column_;
-   uint offset_;
+   uint line_ = 0;
+   uint column_ = 0;
+   uint offset_ = 0;
 };
 
+bool operator==(const SourceLocation &first, const SourceLocation &second);
+
 void PrintTo(const SourceLocation &sourceLocation, ::std::ostream* os);
 
 } // namespace ClangBackEnd
diff --git a/src/tools/clangbackend/ipcsource/sourcerange.cpp b/src/tools/clangbackend/ipcsource/sourcerange.cpp
index 7375988b2b..f069edc9cb 100644
--- a/src/tools/clangbackend/ipcsource/sourcerange.cpp
+++ b/src/tools/clangbackend/ipcsource/sourcerange.cpp
@@ -32,6 +32,8 @@
 
 #include <sourcerangecontainer.h>
 
+#include <ostream>
+
 namespace ClangBackEnd {
 
 SourceRange::SourceRange()
@@ -39,6 +41,11 @@ SourceRange::SourceRange()
 {
 }
 
+SourceRange::SourceRange(const SourceLocation &start, const SourceLocation &end)
+    : cxSourceRange(clang_getRange(start, end))
+{
+}
+
 bool SourceRange::isNull() const
 {
     return clang_Range_isNull(cxSourceRange);
@@ -65,10 +72,33 @@ SourceRangeContainer SourceRange::toSourceRangeContainer() const
                                 end().toSourceLocationContainer());
 }
 
+ClangBackEnd::SourceRange::operator SourceRangeContainer() const
+{
+    return toSourceRangeContainer();
+}
+
+ClangBackEnd::SourceRange::operator CXSourceRange() const
+{
+    return cxSourceRange;
+}
+
 SourceRange::SourceRange(CXSourceRange cxSourceRange)
     : cxSourceRange(cxSourceRange)
 {
 }
 
+bool operator==(const SourceRange &first, const SourceRange &second)
+{
+    return clang_equalRanges(first.cxSourceRange, second.cxSourceRange);
+}
+
+void PrintTo(const SourceRange &sourceRange, ::std::ostream* os)
+{
+    *os << "[";
+    PrintTo(sourceRange.start(), os);
+    *os << ", ";
+    PrintTo(sourceRange.end(), os);
+    *os << "]";
+}
 } // namespace ClangBackEnd
 
diff --git a/src/tools/clangbackend/ipcsource/sourcerange.h b/src/tools/clangbackend/ipcsource/sourcerange.h
index 3c80e4e040..f9b786cf4a 100644
--- a/src/tools/clangbackend/ipcsource/sourcerange.h
+++ b/src/tools/clangbackend/ipcsource/sourcerange.h
@@ -41,9 +41,14 @@ class SourceRange
 {
     friend class Diagnostic;
     friend class FixIt;
+    friend class Cursor;
+    friend class HighlightingInformation;
+    friend bool operator==(const SourceRange &first, const SourceRange &second);
 
 public:
     SourceRange();
+    SourceRange(CXSourceRange cxSourceRange);
+    SourceRange(const SourceLocation &start, const SourceLocation &end);
 
     bool isNull() const;
     bool isValid() const;
@@ -53,13 +58,15 @@ public:
 
     SourceRangeContainer toSourceRangeContainer() const;
 
-private:
-    SourceRange(CXSourceRange cxSourceRange);
+    operator CXSourceRange() const;
+    operator SourceRangeContainer() const;
 
 private:
     CXSourceRange cxSourceRange;
 };
 
+bool operator==(const SourceRange &first, const SourceRange &second);
+void PrintTo(const SourceRange &sourceRange, ::std::ostream* os);
 } // namespace ClangBackEnd
 
 #endif // CLANGBACKEND_SOURCERANGE_H
diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp
index 88e917010f..8769f7caef 100644
--- a/src/tools/clangbackend/ipcsource/translationunit.cpp
+++ b/src/tools/clangbackend/ipcsource/translationunit.cpp
@@ -30,13 +30,17 @@
 
 #include "translationunit.h"
 
+#include "cursor.h"
 #include "clangstring.h"
 #include "codecompleter.h"
 #include "commandlinearguments.h"
 #include "diagnosticcontainer.h"
 #include "diagnosticset.h"
 #include "projectpart.h"
+#include "skippedsourceranges.h"
 #include "sourcelocation.h"
+#include "sourcerange.h"
+#include "highlightinginformations.h"
 #include "translationunitfilenotexitexception.h"
 #include "translationunitisnullexception.h"
 #include "translationunitparseerrorexception.h"
@@ -245,6 +249,53 @@ void TranslationUnit::setDirtyIfDependencyIsMet(const Utf8String &filePath)
     }
 }
 
+SourceLocation TranslationUnit::sourceLocationAt(uint line, uint column) const
+{
+    return SourceLocation(cxTranslationUnit(), filePath(), line, column);
+}
+
+SourceLocation TranslationUnit::sourceLocationAt(const Utf8String &filePath, uint line, uint column) const
+{
+    return SourceLocation(cxTranslationUnit(), filePath, line, column);
+}
+
+SourceRange TranslationUnit::sourceRange(uint fromLine, uint fromColumn, uint toLine, uint toColumn) const
+{
+    return SourceRange(sourceLocationAt(fromLine, fromColumn),
+                       sourceLocationAt(toLine, toColumn));
+}
+
+Cursor TranslationUnit::cursorAt(uint line, uint column) const
+{
+    return clang_getCursor(cxTranslationUnit(), sourceLocationAt(line, column));
+}
+
+Cursor TranslationUnit::cursorAt(const Utf8String &filePath, uint line, uint column) const
+{
+    return clang_getCursor(cxTranslationUnit(), sourceLocationAt(filePath, line, column));
+}
+
+Cursor TranslationUnit::cursor() const
+{
+    return clang_getTranslationUnitCursor(cxTranslationUnit());
+}
+
+HighlightingInformations TranslationUnit::highlightingInformationsInRange(const SourceRange &range) const
+{
+    CXToken *cxTokens = 0;
+    uint cxTokensCount = 0;
+    auto translationUnit = cxTranslationUnit();
+
+    clang_tokenize(translationUnit, range, &cxTokens, &cxTokensCount);
+
+    return HighlightingInformations(translationUnit, cxTokens, cxTokensCount);
+}
+
+SkippedSourceRanges TranslationUnit::skippedSourceRanges() const
+{
+    return SkippedSourceRanges(cxTranslationUnit(), d->filePath.constData());
+}
+
 void TranslationUnit::checkIfNull() const
 {
     if (isNull())
@@ -380,7 +431,8 @@ uint TranslationUnit::defaultOptions()
 {
     return CXTranslationUnit_CacheCompletionResults
          | CXTranslationUnit_PrecompiledPreamble
-         | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
+         | CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
+         | CXTranslationUnit_DetailedPreprocessingRecord;
 }
 
 uint TranslationUnit::unsavedFilesCount() const
diff --git a/src/tools/clangbackend/ipcsource/translationunit.h b/src/tools/clangbackend/ipcsource/translationunit.h
index e44852e473..fd3831cb3e 100644
--- a/src/tools/clangbackend/ipcsource/translationunit.h
+++ b/src/tools/clangbackend/ipcsource/translationunit.h
@@ -52,8 +52,13 @@ class ProjectPart;
 class DiagnosticContainer;
 class DiagnosticSet;
 class FileContainer;
+class HighlightingInformations;
 class TranslationUnits;
 class CommandLineArguments;
+class Cursor;
+class SourceLocation;
+class SourceRange;
+class SkippedSourceRanges;
 
 using time_point = std::chrono::steady_clock::time_point;
 
@@ -111,6 +116,19 @@ public:
 
     CommandLineArguments commandLineArguments() const;
 
+    SourceLocation sourceLocationAt(uint line, uint column) const;
+    SourceLocation sourceLocationAt(const Utf8String &filePath, uint line, uint column) const;
+
+    SourceRange sourceRange(uint fromLine, uint fromColumn, uint toLine, uint toColumn) const;
+
+    Cursor cursorAt(uint line, uint column) const;
+    Cursor cursorAt(const Utf8String &filePath, uint line, uint column) const;
+    Cursor cursor() const;
+
+    HighlightingInformations highlightingInformationsInRange(const SourceRange &range) const;
+
+    SkippedSourceRanges skippedSourceRanges() const;
+
 private:
     void checkIfNull() const;
     void checkIfFileExists() const;
diff --git a/src/tools/clangbackend/ipcsource/type.cpp b/src/tools/clangbackend/ipcsource/type.cpp
new file mode 100644
index 0000000000..a1f78e44eb
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/type.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "type.h"
+
+#include "clangstring.h"
+#include "cursor.h"
+
+#include <utf8string.h>
+
+#include <ostream>
+
+namespace ClangBackEnd {
+
+bool Type::isConstant() const
+{
+    return clang_isConstQualifiedType(cxType);
+}
+
+bool Type::isConstantReference()
+{
+    return isLValueReference() && pointeeType().isConstant();
+}
+
+bool Type::isPointer() const
+{
+    return cxType.kind == CXType_Pointer;
+}
+
+bool Type::isPointerToConstant() const
+{
+    return isPointer() && pointeeType().isConstant();
+}
+
+bool Type::isConstantPointer() const
+{
+    return isPointer() && isConstant();
+}
+
+bool Type::isLValueReference() const
+{
+    return cxType.kind == CXType_LValueReference;
+}
+
+bool Type::isReferencingConstant() const
+{
+    return (isPointer() || isLValueReference()) && pointeeType().isConstant();
+}
+
+bool Type::isOutputParameter() const
+{
+    return (isPointer() || isLValueReference()) && !pointeeType().isConstant();
+}
+
+Utf8String Type::utf8Spelling() const
+{
+    return  ClangString(clang_getTypeSpelling(cxType));
+}
+
+ClangString Type::spelling() const
+{
+    return ClangString(clang_getTypeSpelling(cxType));
+}
+
+int Type::argumentCount() const
+{
+    return clang_getNumArgTypes(cxType);
+}
+
+Type Type::alias() const
+{
+    return clang_getTypedefDeclUnderlyingType(clang_getTypeDeclaration(cxType));
+}
+
+Type Type::canonical() const
+{
+    return clang_getCanonicalType(cxType);
+}
+
+Type Type::classType() const
+{
+    return clang_Type_getClassType(cxType);
+}
+
+Type Type::pointeeType() const
+{
+    return clang_getPointeeType(cxType);
+}
+
+Type Type::argument(int index) const
+{
+    return clang_getArgType(cxType, index);
+}
+
+Cursor Type::declaration() const
+{
+    return clang_getTypeDeclaration(cxType);
+}
+
+CXTypeKind Type::kind() const
+{
+    return cxType.kind;
+}
+
+Type::Type(CXType cxType)
+    : cxType(cxType)
+{
+}
+
+bool operator==(Type first, Type second)
+{
+    return clang_equalTypes(first.cxType, second.cxType);
+}
+
+void PrintTo(CXTypeKind typeKind, ::std::ostream* os)
+{
+    ClangString typeKindSpelling(clang_getTypeKindSpelling(typeKind));
+    *os << typeKindSpelling.cString();
+}
+
+void PrintTo(const Type &type, ::std::ostream* os)
+{
+    ClangString typeKindSpelling(clang_getTypeKindSpelling(type.kind()));
+    *os << typeKindSpelling.cString()
+        << ": \"" << type.spelling().cString() << "\"";
+}
+
+
+} // namespace ClangBackEnd
+
diff --git a/src/tools/clangbackend/ipcsource/type.h b/src/tools/clangbackend/ipcsource/type.h
new file mode 100644
index 0000000000..099bfa4e3e
--- /dev/null
+++ b/src/tools/clangbackend/ipcsource/type.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef CLANGBACKEND_TYPE_H
+#define CLANGBACKEND_TYPE_H
+
+#include <clang-c/Index.h>
+
+#include <iosfwd>
+
+class Utf8String;
+
+namespace ClangBackEnd {
+
+class Cursor;
+class ClangString;
+
+class Type
+{
+    friend class Cursor;
+    friend bool operator==(Type first, Type second);
+
+public:
+    bool isConstant() const;
+    bool isConstantReference();
+    bool isPointer() const;
+    bool isPointerToConstant() const;
+    bool isConstantPointer() const;
+    bool isLValueReference() const;
+    bool isReferencingConstant() const;
+    bool isOutputParameter() const;
+
+    Utf8String utf8Spelling() const;
+    ClangString spelling() const;
+    int argumentCount() const;
+
+    Type alias() const;
+    Type canonical() const;
+    Type classType() const;
+    Type pointeeType() const;
+    Type argument(int index) const;
+
+    Cursor declaration() const;
+
+    CXTypeKind kind() const;
+
+private:
+    Type(CXType cxType);
+
+private:
+    CXType cxType;
+};
+
+bool operator==(Type first, Type second);
+
+void PrintTo(CXTypeKind typeKind, ::std::ostream* os);
+void PrintTo(const Type &type, ::std::ostream* os);
+} // namespace ClangBackEnd
+
+#endif // CLANGBACKEND_TYPE_H
diff --git a/tests/unit/unittest/clangstringtest.cpp b/tests/unit/unittest/clangstringtest.cpp
index 0467de693d..b7ee1982b9 100644
--- a/tests/unit/unittest/clangstringtest.cpp
+++ b/tests/unit/unittest/clangstringtest.cpp
@@ -42,6 +42,8 @@
 
 namespace {
 
+using ::testing::StrEq;
+
 using ClangBackEnd::ClangString;
 
 TEST(ClangString, ConvertToUtf8String)
@@ -87,4 +89,11 @@ TEST(ClangString, MoveSelfAssigment)
 
     ASSERT_FALSE(text.isNull());
 }
+
+TEST(ClangString, SpellingAsCString)
+{
+    ClangString text(CXString{"text", 0});
+
+    ASSERT_THAT(text.cString(), StrEq("text"));
+}
 }
diff --git a/tests/unit/unittest/cursortest.cpp b/tests/unit/unittest/cursortest.cpp
new file mode 100644
index 0000000000..e0e18c1308
--- /dev/null
+++ b/tests/unit/unittest/cursortest.cpp
@@ -0,0 +1,819 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include <clangstring.h>
+#include <cursor.h>
+#include <projectpart.h>
+#include <projects.h>
+#include <sourcelocation.h>
+#include <sourcerange.h>
+#include <translationunit.h>
+#include <translationunits.h>
+#include <unsavedfiles.h>
+
+#include <gmock/gmock.h>
+#include <gmock/gmock-matchers.h>
+#include <gtest/gtest.h>
+#include "gtest-qt-printing.h"
+
+using ClangBackEnd::Cursor;
+using ClangBackEnd::TranslationUnit;
+using ClangBackEnd::UnsavedFiles;
+using ClangBackEnd::ProjectPart;
+using ClangBackEnd::TranslationUnits;
+using ClangBackEnd::ClangString;
+using ClangBackEnd::SourceRange;
+
+using testing::IsNull;
+using testing::NotNull;
+using testing::Gt;
+using testing::Contains;
+using testing::EndsWith;
+using testing::AllOf;
+using testing::Not;
+using testing::IsEmpty;
+using testing::StrEq;
+
+namespace {
+
+struct Data {
+    ClangBackEnd::ProjectParts projects;
+    ClangBackEnd::UnsavedFiles unsavedFiles;
+    ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
+    TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/cursor.cpp"),
+                ProjectPart(Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++11")}),
+                {},
+                translationUnits};
+};
+
+class Cursor : public ::testing::Test
+{
+public:
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+protected:
+    static Data *d;
+    const TranslationUnit &translationUnit = d->translationUnit;
+
+
+};
+
+TEST_F(Cursor, CreateNullCursor)
+{
+    ::Cursor cursor;
+
+    ASSERT_TRUE(cursor.isNull());
+}
+
+TEST_F(Cursor, CompareNullCursors)
+{
+    ::Cursor cursor;
+    ::Cursor cursor2;
+
+    ASSERT_THAT(cursor, cursor2);
+}
+
+TEST_F(Cursor, IsNotValid)
+{
+    ::Cursor cursor;
+
+    ASSERT_FALSE(cursor.isValid());
+}
+
+TEST_F(Cursor, IsValid)
+{
+    auto cursor = translationUnit.cursor();
+
+    ASSERT_TRUE(cursor.isValid());
+}
+
+TEST_F(Cursor, IsTranslationUnit)
+{
+    auto cursor = translationUnit.cursor();
+
+    ASSERT_TRUE(cursor.isTranslationUnit());
+}
+
+TEST_F(Cursor, NullCursorIsNotTranslationUnit)
+{
+    ::Cursor cursor;
+
+    ASSERT_FALSE(cursor.isTranslationUnit());
+}
+
+TEST_F(Cursor, UnifiedSymbolResolution)
+{
+     ::Cursor cursor;
+
+     ASSERT_TRUE(cursor.unifiedSymbolResolution().isEmpty());
+}
+
+TEST_F(Cursor, GetCursorAtLocation)
+{
+    auto cursor = translationUnit.cursorAt(3, 6);
+
+    ASSERT_THAT(cursor.unifiedSymbolResolution(), Utf8StringLiteral("c:@F@function#I#"));
+}
+
+TEST_F(Cursor, GetCursoSourceLocation)
+{
+    auto cursor = translationUnit.cursorAt(3, 6);
+
+    ASSERT_THAT(cursor.sourceLocation(), translationUnit.sourceLocationAt(3, 6));
+}
+
+TEST_F(Cursor, GetCursoSourceRange)
+{
+    auto cursor = translationUnit.cursorAt(3, 6);
+
+    ASSERT_THAT(cursor.sourceRange(), SourceRange(translationUnit.sourceLocationAt(3, 1),
+                                                  translationUnit.sourceLocationAt(6, 2)));
+}
+
+TEST_F(Cursor, Mangling)
+{
+    auto cursor = translationUnit.cursorAt(3, 6);
+
+
+    ASSERT_THAT(cursor.mangling(), Utf8StringLiteral("_Z8functioni"));
+}
+
+TEST_F(Cursor, Spelling)
+{
+    auto cursor = translationUnit.cursorAt(3, 6);
+
+
+    ASSERT_THAT(cursor.spelling().cString(), StrEq("function"));
+}
+
+TEST_F(Cursor, DisplayName)
+{
+    auto cursor = translationUnit.cursorAt(3, 6);
+
+
+    ASSERT_THAT(cursor.displayName(), Utf8StringLiteral("function(int)"));
+}
+
+TEST_F(Cursor, BriefComment)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7);
+
+
+    ASSERT_THAT(cursor.briefComment(), Utf8StringLiteral("A brief comment"));
+}
+
+TEST_F(Cursor, RawComment)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7);
+
+
+    ASSERT_THAT(cursor.rawComment(), Utf8StringLiteral("/**\n * A brief comment\n */"));
+}
+
+TEST_F(Cursor, CommentRange)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7);
+
+
+    ASSERT_THAT(cursor.commentRange(),
+                SourceRange(translationUnit.sourceLocationAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 7, 1),
+                            translationUnit.sourceLocationAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 9, 4)));
+}
+
+TEST_F(Cursor, IsDefinition)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7);
+
+    ASSERT_TRUE(cursor.isDefinition());
+}
+
+TEST_F(Cursor, ForwardDeclarationIsNotDefinition)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 6, 7);
+
+    ASSERT_FALSE(cursor.isDefinition());
+}
+
+TEST_F(Cursor, GetDefinitionOfFowardDeclaration)
+{
+    auto forwardDeclarationcursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 6, 7);
+    auto definitionCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7);
+
+    ASSERT_THAT(forwardDeclarationcursor.definition(), definitionCursor);
+}
+
+TEST_F(Cursor, CallToMethodeIsNotDynamic)
+{
+    auto cursor = translationUnit.cursorAt(18, 5);
+
+    ASSERT_FALSE(cursor.isDynamicCall());
+}
+
+TEST_F(Cursor, CallToAbstractVirtualMethodeIsDynamic)
+{
+    auto cursor = translationUnit.cursorAt(19, 5);
+
+    ASSERT_TRUE(cursor.isDynamicCall());
+}
+
+TEST_F(Cursor, CanonicalCursor)
+{
+    auto forwardDeclarationcursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 6, 7);
+    auto definitionCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7);
+
+    ASSERT_THAT(definitionCursor.canonical(), forwardDeclarationcursor);
+}
+
+TEST_F(Cursor, ReferencedCursor)
+{
+    auto functionCallCursor = translationUnit.cursorAt(18, 5);
+    auto functionCursor = translationUnit.cursorAt(16, 17);
+
+    ASSERT_THAT(functionCallCursor.referenced(), functionCursor);
+}
+
+TEST_F(Cursor, IsVirtual)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 15, 17);
+
+    ASSERT_TRUE(cursor.isVirtualMethod());
+}
+
+TEST_F(Cursor, IsNotPureVirtualOnlyVirtual)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 15, 17);
+
+    ASSERT_FALSE(cursor.isPureVirtualMethod());
+}
+
+TEST_F(Cursor, IsPureVirtual)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 16, 17);
+
+    ASSERT_TRUE(cursor.isPureVirtualMethod());
+}
+
+TEST_F(Cursor, ConstantMethod)
+{
+    auto cursor = translationUnit.cursorAt(31, 18);
+
+    ASSERT_TRUE(cursor.isConstantMethod());
+}
+
+TEST_F(Cursor, IsStaticMethod)
+{
+    auto cursor = translationUnit.cursorAt(36, 18);
+
+    ASSERT_TRUE(cursor.isStaticMethod());
+}
+
+TEST_F(Cursor, TypeSpelling)
+{
+    auto cursor = translationUnit.cursorAt(43, 5);
+
+    ASSERT_THAT(cursor.type().utf8Spelling(), Utf8StringLiteral("lint"));
+}
+
+TEST_F(Cursor, CanonicalTypeSpelling)
+{
+    auto cursor = translationUnit.cursorAt(43, 5);
+
+    ASSERT_THAT(cursor.type().canonical().utf8Spelling(), Utf8StringLiteral("long long"));
+}
+
+TEST_F(Cursor, CanonicalTypeCStringSpelling)
+{
+    auto cursor = translationUnit.cursorAt(43, 5);
+
+    auto spelling = cursor.type().canonical().spelling();
+
+    ASSERT_THAT(spelling.cString(), StrEq("long long"));
+}
+
+TEST_F(Cursor, CanonicalTypeIsNotType)
+{
+    auto cursor = translationUnit.cursorAt(43, 5);
+
+    ASSERT_THAT(cursor.type().canonical(), Not(cursor.type()));
+}
+
+TEST_F(Cursor, TypeDeclartionIsAlias)
+{
+    auto declarationCursor = translationUnit.cursorAt(41, 5);
+    auto lintCursor = translationUnit.cursorAt(39, 11);
+
+    ASSERT_THAT(declarationCursor.type().declaration().type(), lintCursor.type());
+}
+
+TEST_F(Cursor, TypeIsConstantWithoutAliasLookup)
+{
+    auto cursor = translationUnit.cursorAt(45, 16);
+
+    ASSERT_TRUE(cursor.type().isConstant());
+}
+
+TEST_F(Cursor, ClassIsCompoundType)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 10, 7);
+
+    ASSERT_TRUE(cursor.isCompoundType());
+}
+
+TEST_F(Cursor, StructIsCompoundType)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 28, 8);
+
+    ASSERT_TRUE(cursor.isCompoundType());
+}
+
+TEST_F(Cursor, UnionIsCompoundType)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 33, 7);
+
+    ASSERT_TRUE(cursor.isCompoundType());
+}
+
+TEST_F(Cursor, IsDeclaration)
+{
+    auto cursor = translationUnit.cursorAt(41, 10);
+
+    ASSERT_TRUE(cursor.isDeclaration());
+}
+
+TEST_F(Cursor, SemanticParent)
+{
+    auto cursor = translationUnit.cursorAt(43, 6);
+    auto expectedSemanticParent = translationUnit.cursorAt(36, 18);
+
+    auto semanticParent = cursor.semanticParent();
+
+    ASSERT_THAT(semanticParent, expectedSemanticParent);
+}
+
+TEST_F(Cursor, IsLocalVariableInMethod)
+{
+    auto cursor = translationUnit.cursorAt(20, 9);
+
+    ASSERT_TRUE(cursor.isLocalVariable());
+}
+
+TEST_F(Cursor, IsLocalVariableInStaticFunction)
+{
+    auto cursor = translationUnit.cursorAt(43, 5);
+
+    ASSERT_TRUE(cursor.isLocalVariable());
+}
+
+TEST_F(Cursor, IsLocalVariableInTemplateFunction)
+{
+    auto cursor = translationUnit.cursorAt(52, 7);
+
+    ASSERT_TRUE(cursor.isLocalVariable());
+}
+
+TEST_F(Cursor, IsLocalVariableInConversionOperator)
+{
+    auto cursor = translationUnit.cursorAt(57, 9);
+
+    ASSERT_TRUE(cursor.isLocalVariable());
+}
+
+TEST_F(Cursor, IsLocalVariableInOperator)
+{
+    auto cursor = translationUnit.cursorAt(62, 9);
+
+    ASSERT_TRUE(cursor.isLocalVariable());
+}
+
+TEST_F(Cursor, IsLocalVariableInConstructor)
+{
+    auto cursor = translationUnit.cursorAt(13, 9);
+
+    ASSERT_TRUE(cursor.isLocalVariable());
+}
+
+TEST_F(Cursor, IsLocalVariableInDestructor)
+{
+    auto cursor = translationUnit.cursorAt(69, 9);
+
+    ASSERT_TRUE(cursor.isLocalVariable());
+}
+
+TEST_F(Cursor, FindFunctionCaller)
+{
+    auto functionCursor = translationUnit.cursorAt(92, 24);
+    auto structCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 28, 8);
+
+    ASSERT_THAT(functionCursor.functionBaseDeclaration(), structCursor);
+}
+
+TEST_F(Cursor, FindFunctionCallerPointer)
+{
+    auto functionCursor = translationUnit.cursorAt(79, 25);
+    auto structCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 28, 8);
+
+    ASSERT_THAT(functionCursor.functionBaseDeclaration(), structCursor);
+}
+
+TEST_F(Cursor, FindFunctionCallerThis)
+{
+    auto functionCursor = translationUnit.cursorAt(106, 5);
+    auto structCursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 38, 8);
+
+    ASSERT_THAT(functionCursor.functionBaseDeclaration(), structCursor);
+}
+
+TEST_F(Cursor, NonPointerTypeForValue)
+{
+    auto variableCursor = translationUnit.cursorAt(101, 10);
+    auto variablePointerCursor = translationUnit.cursorAt(100, 11);
+
+    ASSERT_THAT(variableCursor.nonPointerTupe(), variablePointerCursor.nonPointerTupe());
+}
+
+TEST_F(Cursor, HasFinalAttributeInFunction)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 30, 18);
+
+    ASSERT_TRUE(cursor.hasFinalFunctionAttribute());
+}
+
+TEST_F(Cursor, HasNotFinalAttributeInFunction)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 15, 17);
+
+    ASSERT_FALSE(cursor.hasFinalFunctionAttribute());
+}
+
+TEST_F(Cursor, HasFinalAttributeInClass)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 28, 8);
+
+    ASSERT_TRUE(cursor.hasFinalClassAttribute());
+}
+
+TEST_F(Cursor, HasNotFinaAttributeInClass)
+{
+    auto cursor = translationUnit.cursorAt(Utf8StringLiteral(TESTDATA_DIR"/cursor.h"), 38, 8);
+
+    ASSERT_FALSE(cursor.hasFinalClassAttribute());
+}
+
+TEST_F(Cursor, HasOutputValues)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(117, 19);
+    auto outputArgumentExpectedCursor = translationUnit.cursorAt(117, 20);
+
+    auto outputArguments = callExpressionCursor.outputArguments();
+
+    ASSERT_THAT(outputArguments.size(), 1);
+    ASSERT_THAT(outputArguments[0], outputArgumentExpectedCursor);
+}
+
+TEST_F(Cursor, HasOnlyInputValues)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(118, 18);
+
+    auto outputArguments = callExpressionCursor.outputArguments();
+
+    ASSERT_THAT(outputArguments, IsEmpty());
+}
+
+TEST_F(Cursor, ArgumentCountIsZero)
+{
+    auto cursor = translationUnit.cursorAt(121, 23);
+
+    auto count = cursor.type().argumentCount();
+
+    ASSERT_THAT(count, 0);
+}
+
+TEST_F(Cursor, ArgumentCountIsTwo)
+{
+    auto cursor = translationUnit.cursorAt(122, 22);
+
+    auto count = cursor.type().argumentCount();
+
+    ASSERT_THAT(count, 2);
+}
+
+TEST_F(Cursor, ArgumentOneIsValue)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(122, 22);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isConstant());
+    ASSERT_THAT(argument.kind(), CXType_Int);
+}
+
+TEST_F(Cursor, ArgumentTwoIsLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(122, 22);
+
+    auto argument = callExpressionCursor.type().argument(1);
+
+    ASSERT_THAT(argument.kind(), CXType_LValueReference);
+}
+
+TEST_F(Cursor, ArgumentTwoIsConstantReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(122, 22);
+
+    auto argumentPointee = callExpressionCursor.type().argument(1);
+
+    ASSERT_TRUE(argumentPointee.isConstantReference());
+}
+
+TEST_F(Cursor, CursorArgumentCount)
+{
+    auto cursor = translationUnit.cursorAt(117, 19);
+
+    ASSERT_THAT(cursor.kind(), CXCursor_CallExpr);
+    ASSERT_THAT(cursor.argumentCount(), 4);
+}
+
+TEST_F(Cursor, CursorArgumentInputValue)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(117, 19);
+    auto declarationReferenceExpressionCursor = translationUnit.cursorAt(117, 20);
+
+    ASSERT_THAT(callExpressionCursor.argument(0), declarationReferenceExpressionCursor);
+}
+
+TEST_F(Cursor, IsConstantLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(125, 26);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isConstantReference());
+}
+
+TEST_F(Cursor, LValueReferenceIsNotConstantLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(124, 21);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isConstantReference());
+}
+
+TEST_F(Cursor, ValueIsNotConstantLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(123, 18);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isConstantReference());
+}
+
+TEST_F(Cursor, PointerToConstantNotConstantLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(126, 20);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isConstantReference());
+}
+
+TEST_F(Cursor, IsLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(124, 21);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isLValueReference());
+}
+
+TEST_F(Cursor, ConstantLValueReferenceIsLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(125, 26);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isLValueReference());
+}
+
+TEST_F(Cursor, ValueIsNotLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(123, 18);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isLValueReference());
+}
+
+TEST_F(Cursor, PointerIsNotLValueReference)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(126, 20);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isLValueReference());
+}
+
+TEST_F(Cursor, PointerToConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(126, 20);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isPointerToConstant());
+}
+
+TEST_F(Cursor, ValueIsNotPointerToConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(123, 18);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isPointerToConstant());
+}
+
+TEST_F(Cursor, PointerNotPointerToConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(127, 13);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isPointerToConstant());
+}
+
+TEST_F(Cursor, ConstantLValueReferenceIsNotPointerToConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(125, 26);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isPointerToConstant());
+}
+
+TEST_F(Cursor, IsConstantPointer)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(128, 21);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isConstantPointer());
+}
+
+TEST_F(Cursor, PointerToConstantIsNotConstantPointer)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(126, 20);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isConstantPointer());
+}
+
+TEST_F(Cursor, ConstValueIsNotConstantPointer)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(129, 23);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isConstantPointer());
+}
+
+TEST_F(Cursor, PointerToConstantIsReferencingConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(126, 20);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isReferencingConstant());
+}
+
+TEST_F(Cursor, ConstantReferenceIsReferencingConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(125, 26);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isReferencingConstant());
+}
+
+TEST_F(Cursor, LValueReferenceIsNotReferencingConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(124, 21);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isReferencingConstant());
+}
+
+TEST_F(Cursor, ValueIsNotReferencingConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(123, 18);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isReferencingConstant());
+}
+
+TEST_F(Cursor, PointerIsNotRefencingConstant)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(127, 13);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isReferencingConstant());
+}
+
+TEST_F(Cursor, PointerIsOutputParameter)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(127, 13);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isOutputParameter());
+}
+
+TEST_F(Cursor, ConstantReferenceIsNotOutputParameter)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(125, 26);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isOutputParameter());
+}
+
+TEST_F(Cursor, PointerToConstantIsNotOutputParameter)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(126, 20);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isOutputParameter()) << argument.isConstant() << argument.pointeeType().isConstant();
+}
+
+TEST_F(Cursor, ConstantPointerIsNotOutputParameter)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(128, 21);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isOutputParameter());
+}
+
+TEST_F(Cursor, ReferenceIsOutputParameter)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(124, 21);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_TRUE(argument.isOutputParameter());
+}
+
+TEST_F(Cursor, ConstReferenceIsNotOutputParameter)
+{
+    auto callExpressionCursor = translationUnit.cursorAt(125, 26);
+
+    auto argument = callExpressionCursor.type().argument(0);
+
+    ASSERT_FALSE(argument.isOutputParameter());
+}
+
+Data *Cursor::d;
+
+void Cursor::SetUpTestCase()
+{
+    d = new Data;
+}
+
+void Cursor::TearDownTestCase()
+{
+    delete d;
+    d = nullptr;
+}
+
+}
diff --git a/tests/unit/unittest/data/cursor.cpp b/tests/unit/unittest/data/cursor.cpp
new file mode 100644
index 0000000000..a492867dd6
--- /dev/null
+++ b/tests/unit/unittest/data/cursor.cpp
@@ -0,0 +1,129 @@
+#include "cursor.h"
+
+void function(int x)
+{
+
+}
+
+namespace Namespace
+{
+SuperClass::SuperClass(int x) noexcept
+  : y(x)
+{
+    int LocalVariable;
+}
+
+int SuperClass::Method()
+{
+    Method();
+    AbstractVirtualMethod(y);
+    int LocalVariable;
+    return y;
+}
+
+int SuperClass::VirtualMethod(int z)
+{
+    AbstractVirtualMethod(z);
+
+    return y;
+}
+
+bool SuperClass::ConstMethod() const
+{
+    return y;
+}
+
+void SuperClass::StaticMethod()
+{
+    using longint = long long int;
+    using lint = longint;
+
+    lint foo;
+
+    foo = 30;
+
+    const lint bar = 20;
+}
+}
+
+template <class T>
+void TemplateFunction(T LocalVariableParameter)
+{
+    T LocalVariable;
+}
+
+Namespace::SuperClass::operator int() const
+{
+    int LocalVariable;
+}
+
+int Namespace::SuperClass::operator ++() const
+{
+    int LocalVariable;
+
+    return LocalVariable;
+}
+
+Namespace::SuperClass::~SuperClass()
+{
+    int LocalVariable;
+}
+
+void Struct::FinalVirtualMethod()
+{
+
+}
+
+void f1(Struct *FindFunctionCaller)
+{
+    FindFunctionCaller->FinalVirtualMethod();
+}
+
+void f2(){
+    Struct *s = new Struct;
+
+    f1(s);
+}
+
+void f3()
+{
+    auto FindFunctionCaller = Struct();
+
+    FindFunctionCaller.FinalVirtualMethod();
+}
+
+
+void f4()
+{
+    Struct s;
+
+    auto *sPointer = &s;
+    auto sValue = s;
+}
+
+void NonFinalStruct::function()
+{
+    FinalVirtualMethod();
+}
+
+void OutputFunction(int &out, int in = 1, const int &in2=2, int *out2=nullptr);
+void InputFunction(const int &value);
+
+void f5()
+{
+    int OutputValue;
+    int InputValue = 20;
+
+    OutputFunction(OutputValue);
+    InputFunction(InputValue);
+}
+
+void ArgumentCountZero();
+void ArgumentCountTwo(int one, const int &two);
+void IntegerValue(int);
+void LValueReference(int &);
+void ConstLValueReference(const int &);
+void PointerToConst(const int *);
+void Pointer(int *);
+void ConstantPointer(int *const);
+void ConstIntegerValue(const int);
diff --git a/tests/unit/unittest/data/cursor.h b/tests/unit/unittest/data/cursor.h
new file mode 100644
index 0000000000..3e9e9a2bfb
--- /dev/null
+++ b/tests/unit/unittest/data/cursor.h
@@ -0,0 +1,42 @@
+
+
+
+namespace Namespace
+{
+class SuperClass;
+/**
+ * A brief comment
+ */
+class SuperClass
+{
+    SuperClass() = default;
+    SuperClass(int x) noexcept;
+    int Method();
+    virtual int VirtualMethod(int z);
+    virtual int AbstractVirtualMethod(int z) = 0;
+    bool ConstMethod() const;
+    static void StaticMethod();
+    operator int() const;
+    int operator ++() const;
+    ~SuperClass();
+
+private:
+    int y;
+};
+}
+
+struct Struct final
+{
+    virtual void FinalVirtualMethod() final;
+};
+
+union Union
+{
+
+};
+
+struct NonFinalStruct
+{
+    virtual void FinalVirtualMethod() final;
+    void function();
+};
diff --git a/tests/unit/unittest/data/highlightinginformations.cpp b/tests/unit/unittest/data/highlightinginformations.cpp
new file mode 100644
index 0000000000..d651fd65e1
--- /dev/null
+++ b/tests/unit/unittest/data/highlightinginformations.cpp
@@ -0,0 +1,385 @@
+auto *Variable       = "Variable";
+auto *u8Variable     = u8"Variable";
+auto *rawVariable    = R"(Variable)";
+auto Character       = 'c';
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+auto integer         = 1;
+auto numFloat        = 1.2f;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+int function(int x)
+{
+    return x;
+}
+
+struct Foo
+{
+    void memberFunction() {}
+};
+
+int functionDeclaration(int x);
+
+struct Foo2
+{
+    void memberFunction();
+};
+
+void f()
+{
+    function(1);
+}
+
+struct ConversionFunction {
+    operator Foo();
+    operator int();
+};
+
+void TypeReference()
+{
+    Foo foo;
+}
+
+void LocalVariableDeclaration()
+{
+    Foo foo;
+
+    foo.memberFunction();
+}
+
+void LocalVariableFunctionArgument(Foo &foo)
+{
+    foo.memberFunction();
+}
+
+struct Foo3 {
+    int ClassMember;
+
+    void ClassMemberReference()
+    {
+        ClassMember++;
+    }
+};
+
+struct Foo4
+{
+    void MemberFunctionReference();
+
+    void function()
+    {
+        MemberFunctionReference();
+    }
+};
+
+struct Foo5
+{
+    void StaticMethod();
+
+    void function()
+    {
+        Foo5::StaticMethod();
+    }
+};
+
+enum Enumeration
+{
+    Enumerator
+};
+
+void f2()
+{
+    Enumeration enumeration;
+
+    enumeration = Enumerator;
+}
+
+class ForwardReference;
+
+class Class
+{ public:
+    Class();
+    ~Class();
+};
+
+ForwardReference *f3()
+{
+    Class ConstructorReference;
+
+    return 0;
+}
+
+union Union
+{
+
+};
+
+Union UnionDeclarationReference;
+
+
+
+
+
+
+
+
+
+namespace NameSpace {
+struct StructInNameSpace {};
+}
+
+namespace NameSpaceAlias = NameSpace;
+
+NameSpace::StructInNameSpace foo6;
+
+class BaseClass {
+public:
+    virtual void VirtualFunction();
+    virtual void FinalVirtualFunction();
+};
+
+
+void f8()
+{
+    BaseClass NonVirtualFunctionCall;
+    NonVirtualFunctionCall.VirtualFunction();
+
+    BaseClass *NonVirtualFunctionCallPointer = new BaseClass();
+    NonVirtualFunctionCallPointer->VirtualFunction();
+}
+
+class DerivedClass : public BaseClass
+{public:
+    void VirtualFunction() override;
+    void FinalVirtualFunction() final;
+};
+
+void f8(BaseClass *VirtualFunctionCallPointer)
+{
+    VirtualFunctionCallPointer->VirtualFunction();
+}
+
+class FinalClass final : public DerivedClass
+{
+    void FinalClassThisCall();
+};
+
+void f8(DerivedClass *FinalVirtualFunctionCallPointer)
+{
+    FinalVirtualFunctionCallPointer->FinalVirtualFunction();
+}
+
+void f9(BaseClass *NonFinalVirtualFunctionCallPointer)
+{
+    NonFinalVirtualFunctionCallPointer->FinalVirtualFunction();
+}
+
+void f10(FinalClass *ClassFinalVirtualFunctionCallPointer)
+{
+    ClassFinalVirtualFunctionCallPointer->VirtualFunction();
+}
+
+class Operator {
+public:
+    Operator operator+=(const Operator &first);
+};
+
+Operator operator+(const Operator &first, const Operator &second);
+
+void f10()
+{
+    auto PlusOperator = Operator() + Operator();
+    Operator PlusAssignOperator;
+    PlusAssignOperator += Operator();
+}
+
+/* Comment */
+
+#define PreprocessorDefinition Class
+#define MacroDefinition(a,b) ((a)>(b)?(a):(b))
+
+void f11()
+{
+    MacroDefinition(2, 4);
+}
+
+#include "highlightinginformations.h"
+
+void f12() {
+GOTO_LABEL:
+
+    goto GOTO_LABEL;
+}
+
+template <class T>
+void TemplateFunction(T v)
+{
+    T XXXXX = v;
+}
+void TemplateReference()
+{
+    TemplateFunction(1);
+//    std::vector<int> TemplateIntance;
+}
+
+
+
+
+template <class T>
+class TemplateFoo {};
+
+
+template <class TemplateTypeParameter = Foo, int NonTypeTemplateParameter = 1, template <class> class TemplateTemplateParameter = TemplateFoo>
+void TemplateFunction(TemplateTypeParameter TemplateParameter)
+{
+    TemplateTypeParameter TemplateTypeParameterReference;
+    auto NonTypeTemplateParameterReference = NonTypeTemplateParameter;
+    TemplateTemplateParameter<TemplateTypeParameter> TemplateTemplateParameterReference;
+}
+
+
+
+void FinalClass::FinalClassThisCall()
+{
+    VirtualFunction();
+}
+
+
+void OutputParameter(int &one, const int &two, int *three=0);
+
+void f12()
+{
+    int One;
+    OutputParameter(One, 2);
+}
+
+#include <highlightinginformations.h>
+
+#define FOREACH(variable, container) \
+    variable; \
+    auto x = container;
+
+#define foreach2 FOREACH
+
+#include <initializer_list>
+
+void f13()
+{
+    auto container = 1;
+    foreach2(int index, container);
+}
+
+class SecondArgumentInMacroExpansionIsField {
+    int container = 1;
+
+    void f()
+    {
+        foreach2(int index, container);
+    }
+};
+
+typedef unsigned uint32;
+
+enum EnumerationType : uint32
+{
+    Other = 0,
+};
+
+
+struct TypeInCast {
+    void function();
+};
+
+void f14()
+{
+    static_cast<void (TypeInCast::*)()>(&TypeInCast::function);
+    reinterpret_cast<void (TypeInCast::*)()>(&TypeInCast::function);
+}
+
+using IntegerAlias = int;
+using SecondIntegerAlias = IntegerAlias;
+using IntegerTypedef = int;
+using Function = void (*)();
+
+
+
+void f15()
+{
+    IntegerAlias integerAlias;
+    SecondIntegerAlias secondIntegerAlias;
+    IntegerTypedef integerTypedef;
+    Function();
+}
+
+class FriendFoo
+{
+public:
+    friend class FooFriend;
+    friend bool operator==(const FriendFoo &first, const FriendFoo &second);
+};
+
+class FieldInitialization
+{
+public:
+    FieldInitialization() :
+        member(0)
+    {}
+
+    int member;
+};
+
+template<class Type>
+void TemplateFunctionCall(Type type)
+{
+    type + type;
+}
+
+void f16()
+{
+    TemplateFunctionCall(1);
+}
+
+
+template <typename T>
+class TemplatedType
+{
+    T value = T();
+};
+
+void f17()
+{
+    TemplatedType<int> TemplatedTypeDeclaration;
+}
diff --git a/tests/unit/unittest/data/highlightinginformations.h b/tests/unit/unittest/data/highlightinginformations.h
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/unit/unittest/data/skippedsourceranges.cpp b/tests/unit/unittest/data/skippedsourceranges.cpp
new file mode 100644
index 0000000000..775393fced
--- /dev/null
+++ b/tests/unit/unittest/data/skippedsourceranges.cpp
@@ -0,0 +1,19 @@
+#if 0
+
+void f();
+
+#endif
+
+#ifndef BLAH
+class Class
+{
+
+};
+#endif
+
+#ifdef BLAH
+class Class
+{
+
+};
+#endif
diff --git a/tests/unit/unittest/highlightinginformationstest.cpp b/tests/unit/unittest/highlightinginformationstest.cpp
new file mode 100644
index 0000000000..c09f12cc17
--- /dev/null
+++ b/tests/unit/unittest/highlightinginformationstest.cpp
@@ -0,0 +1,902 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include <cursor.h>
+#include <clangbackendipc_global.h>
+#include <clangstring.h>
+#include <projectpart.h>
+#include <projects.h>
+#include <sourcelocation.h>
+#include <sourcerange.h>
+#include <highlightinginformation.h>
+#include <highlightinginformations.h>
+#include <translationunit.h>
+#include <translationunits.h>
+#include <unsavedfiles.h>
+
+#include <gmock/gmock.h>
+#include <gmock/gmock-matchers.h>
+#include <gtest/gtest.h>
+#include "gtest-qt-printing.h"
+
+using ClangBackEnd::Cursor;
+using ClangBackEnd::HighlightingInformation;
+using ClangBackEnd::HighlightingInformations;
+using ClangBackEnd::HighlightingType;
+using ClangBackEnd::TranslationUnit;
+using ClangBackEnd::UnsavedFiles;
+using ClangBackEnd::ProjectPart;
+using ClangBackEnd::TranslationUnits;
+using ClangBackEnd::ClangString;
+using ClangBackEnd::SourceRange;
+
+using testing::PrintToString;
+using testing::IsNull;
+using testing::NotNull;
+using testing::Gt;
+using testing::Contains;
+using testing::EndsWith;
+using testing::AllOf;
+using testing::Not;
+using testing::IsEmpty;
+using testing::SizeIs;
+
+namespace {
+
+MATCHER_P4(IsHighlightingInformation, line, column, length, type,
+           std::string(negation ? "isn't " : "is ")
+           + PrintToString(HighlightingInformation(line, column, length, type))
+           )
+{
+    const HighlightingInformation expected(line, column, length, type);
+
+    return arg == expected;
+}
+
+MATCHER_P(HasType, type,
+          std::string(negation ? "isn't " : "is ")
+          + PrintToString(type)
+          )
+{
+    return arg.hasType(type);
+}
+
+struct Data {
+    ClangBackEnd::ProjectParts projects;
+    ClangBackEnd::UnsavedFiles unsavedFiles;
+    ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
+    TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/highlightinginformations.cpp"),
+                ProjectPart(Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++14")}),
+                {},
+                translationUnits};
+};
+
+class HighlightingInformations : public ::testing::Test
+{
+public:
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+    SourceRange sourceRange(uint line, uint columnEnd) const;
+
+protected:
+    static Data *d;
+    const TranslationUnit &translationUnit = d->translationUnit;
+};
+
+TEST_F(HighlightingInformations, CreateNullInformations)
+{
+    ::HighlightingInformations infos;
+
+    ASSERT_TRUE(infos.isNull());
+}
+
+TEST_F(HighlightingInformations, NullInformationsAreEmpty)
+{
+    ::HighlightingInformations infos;
+
+    ASSERT_TRUE(infos.isEmpty());
+}
+
+TEST_F(HighlightingInformations, IsNotNull)
+{
+    const auto aRange = translationUnit.sourceRange(3, 1, 5, 1);
+
+    const auto infos = translationUnit.highlightingInformationsInRange(aRange);
+
+    ASSERT_FALSE(infos.isNull());
+}
+
+TEST_F(HighlightingInformations, IteratorBeginEnd)
+{
+    const auto aRange = translationUnit.sourceRange(3, 1, 5, 1);
+    const auto infos = translationUnit.highlightingInformationsInRange(aRange);
+
+    const auto endIterator = std::next(infos.begin(), infos.size());
+
+    ASSERT_THAT(infos.end(), endIterator);
+}
+
+TEST_F(HighlightingInformations, Size)
+{
+    const auto range = translationUnit.sourceRange(5, 5, 5, 10);
+
+    const auto infos = translationUnit.highlightingInformationsInRange(range);
+
+    ASSERT_THAT(infos.size(), 1);
+}
+
+TEST_F(HighlightingInformations, DISABLED_Keyword)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(5, 12));
+
+    ASSERT_THAT(infos[0], IsHighlightingInformation(5u, 5u, 6u, HighlightingType::Keyword));
+}
+
+TEST_F(HighlightingInformations, StringLiteral)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(1, 29));
+
+    ASSERT_THAT(infos[4], IsHighlightingInformation(1u, 24u, 10u, HighlightingType::StringLiteral));
+}
+
+TEST_F(HighlightingInformations, Utf8StringLiteral)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(2, 33));
+
+    ASSERT_THAT(infos[4], IsHighlightingInformation(2u, 24u, 12u, HighlightingType::StringLiteral));
+}
+
+TEST_F(HighlightingInformations, RawStringLiteral)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(3, 34));
+
+    ASSERT_THAT(infos[4], IsHighlightingInformation(3u, 24u, 13u, HighlightingType::StringLiteral));
+}
+
+TEST_F(HighlightingInformations, CharacterLiteral)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(4, 28));
+
+    ASSERT_THAT(infos[3], IsHighlightingInformation(4u, 24u, 3u, HighlightingType::StringLiteral));
+}
+
+TEST_F(HighlightingInformations, IntegerLiteral)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(23, 26));
+
+    ASSERT_THAT(infos[3], IsHighlightingInformation(23u, 24u, 1u, HighlightingType::NumberLiteral));
+}
+
+TEST_F(HighlightingInformations, FloatLiteral)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(24, 29));
+
+    ASSERT_THAT(infos[3], IsHighlightingInformation(24u, 24u, 4u, HighlightingType::NumberLiteral));
+}
+
+TEST_F(HighlightingInformations, FunctionDefinition)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(45, 20));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(45u, 5u, 8u, HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, MemberFunctionDefinition)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(52, 29));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(52u, 10u, 14u, HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, FunctionDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(55, 32));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(55u, 5u, 19u, HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, MemberFunctionDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(59, 27));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(59u, 10u, 14u, HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, MemberFunctionReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(104, 35));
+
+    ASSERT_THAT(infos[0], IsHighlightingInformation(104u, 9u, 23u, HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, FunctionCall)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(64, 16));
+
+    ASSERT_THAT(infos[0], IsHighlightingInformation(64u, 5u, 8u, HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, TypeConversionFunction)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(68, 20));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(68u, 14u, 3u, HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, InbuiltTypeConversionFunction)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(69, 20));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(69u, 14u, 3u, HighlightingType::Keyword));
+}
+
+TEST_F(HighlightingInformations, TypeReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(74, 13));
+
+    ASSERT_THAT(infos[0], IsHighlightingInformation(74u, 5u, 3u, HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, LocalVariable)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(79, 13));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(79u, 9u, 3u, HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, LocalVariableDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(79, 13));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(79u, 9u, 3u, HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, LocalVariableReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(81, 26));
+
+    ASSERT_THAT(infos[0], IsHighlightingInformation(81u, 5u, 3u, HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, LocalVariableFunctionArgumentDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(84, 45));
+
+    ASSERT_THAT(infos[5], IsHighlightingInformation(84u, 41u, 3u, HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, LocalVariableFunctionArgumentReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(86, 26));
+
+    ASSERT_THAT(infos[0], IsHighlightingInformation(86u, 5u, 3u, HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, ClassVariableDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(90, 21));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(90u, 9u, 11u, HighlightingType::Field));
+}
+
+TEST_F(HighlightingInformations, ClassVariableReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(94, 23));
+
+    ASSERT_THAT(infos[0], IsHighlightingInformation(94u, 9u, 11u, HighlightingType::Field));
+}
+
+TEST_F(HighlightingInformations, StaticMethodDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(110, 25));
+
+    ASSERT_THAT(infos[1], IsHighlightingInformation(110u, 10u, 12u, HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, StaticMethodReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(114, 30));
+
+    ASSERT_THAT(infos[2], IsHighlightingInformation(114u, 15u, 12u, HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, Enumeration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(118, 17));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Enumeration));
+}
+
+TEST_F(HighlightingInformations, Enumerator)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(120, 15));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Enumeration));
+}
+
+TEST_F(HighlightingInformations, EnumerationReferenceDeclarationType)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(125, 28));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Enumeration));
+}
+
+TEST_F(HighlightingInformations, EnumerationReferenceDeclarationVariable)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(125, 28));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, EnumerationReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(127, 30));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, EnumeratorReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(127, 30));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::Enumeration));
+}
+
+TEST_F(HighlightingInformations, ClassForwardDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(130, 12));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, ConstructorDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(134, 13));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, DestructorDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(135, 15));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, ClassForwardDeclarationReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(138, 23));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, ClassTypeReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(140, 32));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, ConstructorReferenceVariable)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(140, 32));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, UnionDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(145, 12));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, UnionDeclarationReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(150, 33));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, GlobalVariable)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(150, 33));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::GlobalVariable));
+}
+
+TEST_F(HighlightingInformations, StructDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(50, 11));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, NameSpace)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(160, 22));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, NameSpaceAlias)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(164, 38));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, NameSpaceReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(166, 35));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, VirtualFunction)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(170, 35));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::VirtualFunction));
+}
+
+TEST_F(HighlightingInformations, DISABLED_NonVirtualFunctionCall)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(177, 46));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, DISABLED_NonVirtualFunctionCallPointer)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(180, 54));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, VirtualFunctionCallPointer)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(192, 51));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::VirtualFunction));
+}
+
+TEST_F(HighlightingInformations, FinalVirtualFunctionCallPointer)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(202, 61));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, NonFinalVirtualFunctionCallPointer)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(207, 61));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::VirtualFunction));
+}
+
+TEST_F(HighlightingInformations, PlusOperator)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(224, 49));
+
+    ASSERT_THAT(infos[6], HasType(HighlightingType::Operator));
+}
+
+TEST_F(HighlightingInformations, PlusAssignOperator)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(226, 24));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Operator));
+}
+
+TEST_F(HighlightingInformations, Comment)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(229, 14));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Comment));
+}
+
+TEST_F(HighlightingInformations, PreprocessingDirective)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(231, 37));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Preprocessor));
+}
+
+TEST_F(HighlightingInformations, PreprocessorMacroDefinition)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(231, 37));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::PreprocessorDefinition));
+}
+
+TEST_F(HighlightingInformations, PreprocessorFunctionMacroDefinition)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(232, 47));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::PreprocessorDefinition));
+}
+
+TEST_F(HighlightingInformations, PreprocessorMacroExpansion)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(236, 27));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::PreprocessorExpansion));
+}
+
+TEST_F(HighlightingInformations, PreprocessorMacroExpansionArgument)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(236, 27));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::NumberLiteral));
+}
+
+TEST_F(HighlightingInformations, PreprocessorInclusionDirective)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(239, 18));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::StringLiteral));
+}
+
+TEST_F(HighlightingInformations, GotoLabelStatement)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(242, 12));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Label));
+}
+
+TEST_F(HighlightingInformations, GotoLabelStatementReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(244, 21));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Label));
+}
+
+TEST_F(HighlightingInformations, TemplateReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(254, 25));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, TemplateTypeParameter)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135));
+
+    ASSERT_THAT(infos[3], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, TemplateDefaultParameter)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135));
+
+    ASSERT_THAT(infos[5], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, NonTypeTemplateParameter)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135));
+
+    ASSERT_THAT(infos[8], HasType(HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, NonTypeTemplateParameterDefaultArgument)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135));
+
+    ASSERT_THAT(infos[10], HasType(HighlightingType::NumberLiteral));
+}
+
+TEST_F(HighlightingInformations, TemplateTemplateParameter)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135));
+
+    ASSERT_THAT(infos[17], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, TemplateTemplateParameterDefaultArgument)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(265, 135));
+
+    ASSERT_THAT(infos[19], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, TemplateFunctionDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(266, 63));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, TemplateTypeParameterReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(268, 58));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, TemplateTypeParameterDeclarationReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(268, 58));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, NonTypeTemplateParameterReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(269, 71));
+
+    ASSERT_THAT(infos[3], HasType(HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, NonTypeTemplateParameterReferenceReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(269, 71));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, TemplateTemplateParameterReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(270, 89));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, TemplateTemplateContainerParameterReference)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(270, 89));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, TemplateTemplateParameterReferenceVariable)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(270, 89));
+
+    ASSERT_THAT(infos[4], HasType(HighlightingType::LocalVariable));
+}
+
+TEST_F(HighlightingInformations, ClassFinalVirtualFunctionCallPointer)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(212, 61));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, ClassFinalVirtualFunctionCall)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(277, 23));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, HasFunctionArguments)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(286, 29));
+
+    ASSERT_TRUE(infos[1].hasFunctionArguments());
+}
+
+TEST_F(HighlightingInformations, NoOutputFunctionArguments)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(285, 13));
+
+    auto outputFunctionArguments = infos[1].outputFunctionArguments();
+
+    ASSERT_THAT(outputFunctionArguments, IsEmpty());
+}
+
+TEST_F(HighlightingInformations, DISABLED_OneOutputFunctionArguments)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(285, 13));
+
+    auto outputFunctionArguments = infos[1].outputFunctionArguments();
+
+    ASSERT_THAT(outputFunctionArguments, SizeIs(1));
+}
+
+TEST_F(HighlightingInformations, PreprocessorInclusionDirectiveWithAngleBrackets )
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(289, 38));
+
+    ASSERT_THAT(infos[3], HasType(HighlightingType::StringLiteral));
+}
+
+TEST_F(HighlightingInformations, ArgumentInMacroExpansionIsKeyword)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(302, 36));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::Keyword));
+}
+
+TEST_F(HighlightingInformations, DISABLED_FirstArgumentInMacroExpansionIsLocalVariable)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(302, 36));
+
+    ASSERT_THAT(infos[3], HasType(HighlightingType::Invalid));
+}
+
+TEST_F(HighlightingInformations, DISABLED_SecondArgumentInMacroExpansionIsLocalVariable)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(302, 36));
+
+    ASSERT_THAT(infos[5], HasType(HighlightingType::Invalid));
+}
+
+TEST_F(HighlightingInformations, DISABLED_SecondArgumentInMacroExpansionIsField)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(310, 40));
+
+    ASSERT_THAT(infos[5], HasType(HighlightingType::Invalid));
+}
+
+
+TEST_F(HighlightingInformations, DISABLED_EnumerationType)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(316, 30));
+
+    ASSERT_THAT(infos[3], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, TypeInStaticCast)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(328, 64));
+
+    ASSERT_THAT(infos[4], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, StaticCastIsKeyword)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(328, 64));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Keyword));
+}
+
+TEST_F(HighlightingInformations, StaticCastPunctationIsInvalid)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(328, 64));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Invalid));
+    ASSERT_THAT(infos[3], HasType(HighlightingType::Invalid));
+    ASSERT_THAT(infos[5], HasType(HighlightingType::Invalid));
+}
+
+TEST_F(HighlightingInformations, TypeInReinterpretCast)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(329, 69));
+
+    ASSERT_THAT(infos[4], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, IntegerAliasDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(333, 41));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, IntegerAlias)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(341, 31));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, SecondIntegerAlias)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(342, 43));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, IntegerTypedef)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(343, 35));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, FunctionAlias)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(344, 16));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, FriendTypeDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(350, 28));
+
+    ASSERT_THAT(infos[2], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, FriendArgumentTypeDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(351, 65));
+
+    ASSERT_THAT(infos[6], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, DISABLED_FriendArgumentDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(351, 65));
+
+    ASSERT_THAT(infos[8], HasType(HighlightingType::Invalid));
+}
+
+TEST_F(HighlightingInformations, FieldInitialization)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(358, 18));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Field));
+}
+
+TEST_F(HighlightingInformations, TemplateFunctionCall)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(372, 29));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Function));
+}
+
+TEST_F(HighlightingInformations, TemplatedType)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(377, 21));
+
+    ASSERT_THAT(infos[1], HasType(HighlightingType::Type));
+}
+
+TEST_F(HighlightingInformations, TemplatedTypeDeclaration)
+{
+    const auto infos = translationUnit.highlightingInformationsInRange(sourceRange(384, 49));
+
+    ASSERT_THAT(infos[0], HasType(HighlightingType::Type));
+}
+
+Data *HighlightingInformations::d;
+
+void HighlightingInformations::SetUpTestCase()
+{
+    d = new Data;
+}
+
+void HighlightingInformations::TearDownTestCase()
+{
+    delete d;
+    d = nullptr;
+}
+
+ClangBackEnd::SourceRange HighlightingInformations::sourceRange(uint line, uint columnEnd) const
+{
+    return translationUnit.sourceRange(line, 1, line, columnEnd);
+}
+
+}
diff --git a/tests/unit/unittest/skippedsourcerangestest.cpp b/tests/unit/unittest/skippedsourcerangestest.cpp
new file mode 100644
index 0000000000..b37b872690
--- /dev/null
+++ b/tests/unit/unittest/skippedsourcerangestest.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, The Qt Company gives you certain additional
+** rights.  These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include <cursor.h>
+#include <clangstring.h>
+#include <projectpart.h>
+#include <projects.h>
+#include <skippedsourceranges.h>
+#include <sourcelocation.h>
+#include <sourcerange.h>
+#include <translationunit.h>
+#include <translationunits.h>
+#include <unsavedfiles.h>
+
+#include <sourcerangecontainer.h>
+
+#include <QVector>
+
+#include <gmock/gmock.h>
+#include <gmock/gmock-matchers.h>
+#include <gtest/gtest.h>
+#include "gtest-qt-printing.h"
+
+using ClangBackEnd::Cursor;
+using ClangBackEnd::TranslationUnit;
+using ClangBackEnd::UnsavedFiles;
+using ClangBackEnd::ProjectPart;
+using ClangBackEnd::TranslationUnits;
+using ClangBackEnd::ClangString;
+using ClangBackEnd::SourceRange;
+using ClangBackEnd::SkippedSourceRanges;
+
+using testing::IsNull;
+using testing::NotNull;
+using testing::Gt;
+using testing::Contains;
+using testing::EndsWith;
+using testing::AllOf;
+using testing::Not;
+using testing::IsEmpty;
+using testing::SizeIs;
+using testing::PrintToString;
+
+namespace {
+
+MATCHER_P4(IsSourceLocation, filePath, line, column, offset,
+           std::string(negation ? "isn't" : "is")
+           + " source location with file path "+ PrintToString(filePath)
+           + ", line " + PrintToString(line)
+           + ", column " + PrintToString(column)
+           + " and offset " + PrintToString(offset)
+           )
+{
+    if (!arg.filePath().endsWith(filePath)
+     || arg.line() != line
+     || arg.column() != column
+     || arg.offset() != offset) {
+        return false;
+    }
+
+    return true;
+}
+
+struct Data {
+    ClangBackEnd::ProjectParts projects;
+    ClangBackEnd::UnsavedFiles unsavedFiles;
+    ClangBackEnd::TranslationUnits translationUnits{projects, unsavedFiles};
+    Utf8String filePath = Utf8StringLiteral(TESTDATA_DIR"/skippedsourceranges.cpp");
+    TranslationUnit translationUnit{filePath,
+                ProjectPart(Utf8StringLiteral("projectPartId"),
+                            {Utf8StringLiteral("-std=c++11"),Utf8StringLiteral("-DBLAH")}),
+                {},
+                translationUnits};
+};
+
+class SkippedSourceRanges : public ::testing::Test
+{
+public:
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+protected:
+    static Data *d;
+    const TranslationUnit &translationUnit = d->translationUnit;
+    const Utf8String &filePath = d->filePath;
+    const ::SkippedSourceRanges skippedSourceRanges{d->translationUnit.skippedSourceRanges()};
+};
+
+Data *SkippedSourceRanges::d;
+
+TEST_F(SkippedSourceRanges, RangeWithZero)
+{
+    auto ranges = skippedSourceRanges.sourceRanges();
+
+    ASSERT_THAT(ranges, SizeIs(2));
+}
+
+TEST_F(SkippedSourceRanges, RangeOne)
+{
+    auto ranges = skippedSourceRanges.sourceRanges();
+
+    ASSERT_THAT(ranges[0].start(), IsSourceLocation(filePath, 1, 2, 1));
+    ASSERT_THAT(ranges[0].end(), IsSourceLocation(filePath, 5, 7, 24));
+}
+
+TEST_F(SkippedSourceRanges, RangeTwo)
+{
+    auto ranges = skippedSourceRanges.sourceRanges();
+
+    ASSERT_THAT(ranges[1].start(), IsSourceLocation(filePath, 7, 2, 27));
+    ASSERT_THAT(ranges[1].end(), IsSourceLocation(filePath, 12, 7, 63));
+}
+
+TEST_F(SkippedSourceRanges, RangeContainerSize)
+{
+    auto ranges = skippedSourceRanges.toSourceRangeContainers();
+
+    ASSERT_THAT(ranges, SizeIs(2));
+}
+
+void SkippedSourceRanges::SetUpTestCase()
+{
+    d = new Data;
+}
+
+void SkippedSourceRanges::TearDownTestCase()
+{
+    delete d;
+    d = nullptr;
+}
+
+}
diff --git a/tests/unit/unittest/sourcelocationtest.cpp b/tests/unit/unittest/sourcelocationtest.cpp
index 9db922c282..9213d9359c 100644
--- a/tests/unit/unittest/sourcelocationtest.cpp
+++ b/tests/unit/unittest/sourcelocationtest.cpp
@@ -50,13 +50,13 @@ using ClangBackEnd::ProjectPart;
 using ClangBackEnd::SourceLocation;
 using ClangBackEnd::TranslationUnit;
 using ClangBackEnd::UnsavedFiles;
+
 using testing::EndsWith;
+using testing::Not;
 
 namespace {
 
-class SourceLocation : public ::testing::Test
-{
-protected:
+struct Data {
     ProjectPart projectPart{Utf8StringLiteral("projectPartId")};
     ClangBackEnd::ProjectParts projects;
     ClangBackEnd::UnsavedFiles unsavedFiles;
@@ -68,7 +68,18 @@ protected:
     DiagnosticSet diagnosticSet{translationUnit.diagnostics()};
     Diagnostic diagnostic{diagnosticSet.front()};
     ::SourceLocation sourceLocation{diagnostic.location()};
+};
 
+class SourceLocation : public ::testing::Test
+{
+public:
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+protected:
+    static Data *d;
+    const ::SourceLocation &sourceLocation = d->sourceLocation;
+    const TranslationUnit &translationUnit = d->translationUnit;
 };
 
 TEST_F(SourceLocation, FilePath)
@@ -91,4 +102,27 @@ TEST_F(SourceLocation, Offset)
     ASSERT_THAT(sourceLocation.offset(), 18);
 }
 
+TEST_F(SourceLocation, Create)
+{
+    ASSERT_THAT(translationUnit.sourceLocationAt(4, 1), sourceLocation);
+}
+
+TEST_F(SourceLocation, NotEqual)
+{
+    ASSERT_THAT(translationUnit.sourceLocationAt(3, 1), Not(sourceLocation));
+}
+
+Data *SourceLocation::d;
+
+void SourceLocation::SetUpTestCase()
+{
+    d = new Data;
+}
+
+void SourceLocation::TearDownTestCase()
+{
+    delete d;
+    d = nullptr;
+}
+
 }
diff --git a/tests/unit/unittest/sourcerangetest.cpp b/tests/unit/unittest/sourcerangetest.cpp
index 771bd49ccf..b517c42380 100644
--- a/tests/unit/unittest/sourcerangetest.cpp
+++ b/tests/unit/unittest/sourcerangetest.cpp
@@ -51,7 +51,9 @@ using ClangBackEnd::UnsavedFiles;
 using ClangBackEnd::Diagnostic;
 using ClangBackEnd::SourceRange;
 using ClangBackEnd::TranslationUnits;
+
 using testing::PrintToString;
+using testing::IsEmpty;
 
 namespace {
 
@@ -73,9 +75,7 @@ MATCHER_P4(IsSourceLocation, filePath, line, column, offset,
     return true;
 }
 
-class SourceRange : public ::testing::Test
-{
-protected:
+struct Data {
     ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-pedantic")}};
     ClangBackEnd::ProjectParts projects;
     ClangBackEnd::UnsavedFiles unsavedFiles;
@@ -90,6 +90,20 @@ protected:
     ::SourceRange sourceRange{diagnostic.ranges().front()};
 };
 
+class SourceRange : public ::testing::Test
+{
+public:
+    static void SetUpTestCase();
+    static void TearDownTestCase();
+
+protected:
+    static Data *d;
+    const ::SourceRange &sourceRange = d->sourceRange;
+    const Diagnostic &diagnostic = d->diagnostic;
+    const Diagnostic &diagnosticWithFilteredOutInvalidRange = d->diagnosticWithFilteredOutInvalidRange;
+    const TranslationUnit &translationUnit = d->translationUnit;
+};
+
 TEST_F(SourceRange, IsNull)
 {
     ::SourceRange sourceRange;
@@ -125,9 +139,34 @@ TEST_F(SourceRange, End)
                                                       44u));
 }
 
+TEST_F(SourceRange, Create)
+{
+    ASSERT_THAT(sourceRange, ::SourceRange(sourceRange.start(), sourceRange.end()));
+}
+
+TEST_F(SourceRange, SourceRangeFromTranslationUnit)
+{
+    auto sourceRangeFromTranslationUnit = translationUnit.sourceRange(8u, 5u, 8u, 6u);
+
+    ASSERT_THAT(sourceRangeFromTranslationUnit, sourceRange);
+}
+
 TEST_F(SourceRange, InvalidRangeIsFilteredOut)
 {
-    ASSERT_TRUE(diagnosticWithFilteredOutInvalidRange.ranges().empty());
+    ASSERT_THAT(diagnosticWithFilteredOutInvalidRange.ranges(), IsEmpty());
+}
+
+Data *SourceRange::d;
+
+void SourceRange::SetUpTestCase()
+{
+    d = new Data;
+}
+
+void SourceRange::TearDownTestCase()
+{
+    delete d;
+    d = nullptr;
 }
 
 }
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 193f1caa68..6fe2d25f2e 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -53,7 +53,10 @@ SOURCES += \
     translationunittest.cpp \
     unsavedfilestest.cpp \
     utf8test.cpp \
-    senddocumenttrackertest.cpp
+    senddocumenttrackertest.cpp \
+    cursortest.cpp \
+    highlightinginformationstest.cpp \
+    skippedsourcerangestest.cpp
 
 HEADERS += \
     gtest-qt-printing.h \
-- 
GitLab