From f49a1d721c8be7d49bc0831ffa7316f2ec4f383f Mon Sep 17 00:00:00 2001
From: Marco Bubke <marco.bubke@qt.io>
Date: Mon, 21 Aug 2017 12:00:27 +0200
Subject: [PATCH] Clang: Add symbol storage

Extend file path cache to 64 bit integer.

Change-Id: I5627f13d59a3214f389087038482cbcc8d0eb484
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
---
 src/libs/clangsupport/stringcache.h           |  60 +++---
 src/libs/clangsupport/stringcachefwd.h        |   5 +-
 src/libs/sqlite/sqlitestatement.h             | 148 ++++++-------
 src/libs/utils/smallstringview.h              |   2 +
 .../clangpchmanagerbackendmain.cpp            |   4 +-
 .../source/clangpathwatcher.h                 |  38 ++--
 .../source/collectincludesaction.h            |  16 +-
 .../collectincludespreprocessorcallbacks.h    |  20 +-
 .../source/collectincludestoolaction.h        |  16 +-
 .../clangpchmanagerbackend/source/idpaths.h   |   4 +-
 .../source/includecollector.cpp               |   4 +-
 .../source/includecollector.h                 |   8 +-
 .../source/pchcreator.cpp                     |  10 +-
 .../source/pchcreator.h                       |  12 +-
 .../source/pchmanagerserver.cpp               |   2 +-
 .../source/pchmanagerserver.h                 |   4 +-
 .../source/clangquery.cpp                     |   2 +-
 .../source/clangquery.h                       |   4 +-
 .../source/clangquerygatherer.cpp             |   4 +-
 .../source/clangquerygatherer.h               |   6 +-
 .../source/clangrefactoringbackend-source.pri |   7 +-
 .../source/collectsymbolsastvisitor.h         |  11 +-
 .../source/refactoringserver.h                |   2 +-
 .../source/sourcelocationentry.h              |  12 +-
 .../source/sourcerangeextractor.cpp           |   4 +-
 .../source/sourcerangeextractor.h             |   6 +-
 .../source/storagesqlitestatementfactory.h    | 180 ++++++++++++++++
 .../source/symbolentry.h                      |   6 +-
 .../source/symbolstorage.cpp                  |  30 +++
 .../source/symbolstorage.h                    | 155 +++++++++++++
 .../source/symbolstorageinterface.h           |   2 +-
 tests/unit/unittest/clangpathwatcher-test.cpp |   7 +-
 tests/unit/unittest/clangquery-test.cpp       |   4 +-
 .../unit/unittest/clangquerygatherer-test.cpp |   2 +-
 tests/unit/unittest/includecollector-test.cpp |   2 +-
 tests/unit/unittest/mocksqlitedatabase.h      |  41 ++++
 .../unit/unittest/mocksqlitereadstatement.cpp |  76 +++++++
 tests/unit/unittest/mocksqlitereadstatement.h |  92 ++++++++
 .../unit/unittest/mocksqlitewritestatement.h  |  59 +++++
 tests/unit/unittest/pchcreator-test.cpp       |   2 +-
 tests/unit/unittest/pchmanagerserver-test.cpp |   2 +-
 .../unittest/sourcerangeextractor-test.cpp    |   2 +-
 tests/unit/unittest/sqlitestatement-test.cpp  |   1 -
 .../storagesqlitestatementfactory-test.cpp    | 186 ++++++++++++++++
 tests/unit/unittest/stringcache-test.cpp      |  49 +++--
 tests/unit/unittest/symbolscollector-test.cpp |   5 +-
 tests/unit/unittest/symbolstorage-test.cpp    | 203 ++++++++++++++++++
 tests/unit/unittest/unittest.pro              |  11 +-
 48 files changed, 1297 insertions(+), 231 deletions(-)
 create mode 100644 src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h
 create mode 100644 src/tools/clangrefactoringbackend/source/symbolstorage.cpp
 create mode 100644 src/tools/clangrefactoringbackend/source/symbolstorage.h
 create mode 100644 tests/unit/unittest/mocksqlitedatabase.h
 create mode 100644 tests/unit/unittest/mocksqlitereadstatement.cpp
 create mode 100644 tests/unit/unittest/mocksqlitereadstatement.h
 create mode 100644 tests/unit/unittest/mocksqlitewritestatement.h
 create mode 100644 tests/unit/unittest/storagesqlitestatementfactory-test.cpp
 create mode 100644 tests/unit/unittest/symbolstorage-test.cpp

diff --git a/src/libs/clangsupport/stringcache.h b/src/libs/clangsupport/stringcache.h
index a6f8d4633e5..804be33541f 100644
--- a/src/libs/clangsupport/stringcache.h
+++ b/src/libs/clangsupport/stringcache.h
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#include "stringcachefwd.h"
+
 #include <utils/smallstringview.h>
 #include <utils/smallstringfwd.h>
 
@@ -52,11 +54,11 @@ public:
     void unlock() {}
 };
 
-template <typename StringType>
+template <typename StringType, typename IndexType>
 class StringCacheEntry
 {
 public:
-    StringCacheEntry(StringType &&string, uint id)
+    StringCacheEntry(StringType &&string, IndexType id)
         : string(std::move(string)),
           id(id)
     {}
@@ -77,22 +79,27 @@ public:
     }
 
     StringType string;
-    uint id;
+    IndexType id;
 };
 
-template <typename StringType>
-using StringCacheEntries = std::vector<StringCacheEntry<StringType>>;
+template <typename StringType, typename IndexType>
+using StringCacheEntries = std::vector<StringCacheEntry<StringType, IndexType>>;
+
+using FileCacheCacheEntry = StringCacheEntry<Utils::PathString, FilePathIndex>;
+using FileCacheCacheEntries = std::vector<FileCacheCacheEntry>;
 
 template <typename StringType,
-          typename Mutex = NonLockingMutex>
+          typename IndexType,
+          typename Mutex>
 class StringCache
 {
-    using const_iterator = typename StringCacheEntries<StringType>::const_iterator;
+    using CacheEnties = StringCacheEntries<StringType, IndexType>;
+    using const_iterator = typename CacheEnties::const_iterator;
 
     class Found
     {
     public:
-        typename StringCacheEntries<StringType>::const_iterator iterator;
+        typename CacheEnties::const_iterator iterator;
         bool wasFound;
     };
 
@@ -103,14 +110,14 @@ public:
         m_indices.reserve(1024);
     }
 
-    void populate(StringCacheEntries<StringType> &&entries)
+    void populate(CacheEnties &&entries)
     {
         uncheckedPopulate(std::move(entries));
 
         checkEntries();
     }
 
-    void uncheckedPopulate(StringCacheEntries<StringType> &&entries)
+    void uncheckedPopulate(CacheEnties &&entries)
     {
         std::sort(entries.begin(), entries.end());
 
@@ -123,7 +130,7 @@ public:
     }
 
 
-    uint stringId(Utils::SmallStringView stringView)
+    IndexType stringId(Utils::SmallStringView stringView)
     {
         std::lock_guard<Mutex> lock(m_mutex);
 
@@ -136,11 +143,11 @@ public:
     }
 
     template <typename Container>
-    std::vector<uint> stringIds(const Container &strings)
+    std::vector<IndexType> stringIds(const Container &strings)
     {
         std::lock_guard<Mutex> lock(m_mutex);
 
-        std::vector<uint> ids;
+        std::vector<IndexType> ids;
         ids.reserve(strings.size());
 
         std::transform(strings.begin(),
@@ -151,19 +158,19 @@ public:
         return ids;
     }
 
-    std::vector<uint> stringIds(std::initializer_list<StringType> strings)
+    std::vector<IndexType> stringIds(std::initializer_list<StringType> strings)
     {
         return stringIds<std::initializer_list<StringType>>(strings);
     }
 
-    Utils::SmallStringView string(uint id) const
+    Utils::SmallStringView string(IndexType id) const
     {
         std::lock_guard<Mutex> lock(m_mutex);
 
         return m_strings.at(m_indices.at(id)).string;
     }
 
-    std::vector<StringType> strings(const std::vector<uint> &ids) const
+    std::vector<StringType> strings(const std::vector<IndexType> &ids) const
     {
         std::lock_guard<Mutex> lock(m_mutex);
 
@@ -173,7 +180,7 @@ public:
         std::transform(ids.begin(),
                        ids.end(),
                        std::back_inserter(strings),
-                       [&] (uint id) { return m_strings.at(m_indices.at(id)).string; });
+                       [&] (IndexType id) { return m_strings.at(m_indices.at(id)).string; });
 
         return strings;
     }
@@ -191,24 +198,24 @@ private:
         return {range.first, range.first != range.second};
     }
 
-    void incrementLargerOrEqualIndicesByOne(uint newIndex)
+    void incrementLargerOrEqualIndicesByOne(IndexType newIndex)
     {
         std::transform(m_indices.begin(),
                        m_indices.end(),
                        m_indices.begin(),
-                       [&] (uint index) {
+                       [&] (IndexType index) {
             return index >= newIndex ? ++index : index;
         });
     }
 
-    uint insertString(const_iterator beforeIterator,
+    IndexType insertString(const_iterator beforeIterator,
                       Utils::SmallStringView stringView)
     {
-        auto id = uint(m_indices.size());
+        auto id = IndexType(m_indices.size());
 
         auto inserted = m_strings.emplace(beforeIterator, StringType(stringView), id);
 
-        auto newIndex = uint(std::distance(m_strings.begin(), inserted));
+        auto newIndex = IndexType(std::distance(m_strings.begin(), inserted));
 
         incrementLargerOrEqualIndicesByOne(newIndex);
 
@@ -226,12 +233,13 @@ private:
     }
 
 private:
-    StringCacheEntries<StringType> m_strings;
-    std::vector<uint> m_indices;
+    CacheEnties m_strings;
+    std::vector<IndexType> m_indices;
     mutable Mutex m_mutex;
 };
 
-template <typename Mutex = NonLockingMutex>
-using FilePathCache = StringCache<Utils::PathString, Mutex>;
+template <typename Mutex>
+using FilePathCache = StringCache<Utils::PathString, FilePathIndex, Mutex>;
+using FilePathIndices = std::vector<FilePathIndex>;
 
 } // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/stringcachefwd.h b/src/libs/clangsupport/stringcachefwd.h
index 35b8534254e..4a12bfee691 100644
--- a/src/libs/clangsupport/stringcachefwd.h
+++ b/src/libs/clangsupport/stringcachefwd.h
@@ -29,14 +29,17 @@
 
 namespace ClangBackEnd {
 
+using FilePathIndex = long long int;
+
 class NonLockingMutex;
 
 template <typename StringType,
+          typename IndexType,
           typename Mutex>
 class StringCache;
 
 template <typename Mutex = NonLockingMutex>
-using FilePathCache = StringCache<Utils::PathString, Mutex>;
+using FilePathCache = StringCache<Utils::PathString, FilePathIndex, Mutex>;
 
 } // namespace ClangBackEnd
 
diff --git a/src/libs/sqlite/sqlitestatement.h b/src/libs/sqlite/sqlitestatement.h
index 09c75c16d97..d9bd87a2ee4 100644
--- a/src/libs/sqlite/sqlitestatement.h
+++ b/src/libs/sqlite/sqlitestatement.h
@@ -83,27 +83,27 @@ protected:
     {
     }
 
-    template<typename... Values>
-    void bindValues(Values... values)
+    template<typename... ValueType>
+    void bindValues(ValueType... values)
     {
         bindValuesByIndex(1, values...);
     }
 
-    template<typename... Values>
-    void write(Values... values)
+    template<typename... ValueType>
+    void write(ValueType... values)
     {
         bindValuesByIndex(1, values...);
         execute();
     }
 
-    template<typename... Values>
-    void bindNameValues(Values... values)
+    template<typename... ValueType>
+    void bindNameValues(ValueType... values)
     {
         bindValuesByName(values...);
     }
 
-    template<typename... Values>
-    void writeNamed(Values... values)
+    template<typename... ValueType>
+    void writeNamed(ValueType... values)
     {
         bindValuesByName(values...);
         execute();
@@ -117,45 +117,45 @@ protected:
     void setBindingColumnNames(const Utils::SmallStringVector &bindingColumnNames);
     const Utils::SmallStringVector &bindingColumnNames() const;
 
-    template <typename... ResultType>
-    std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize)
+    template <typename... ResultTypes>
+    std::vector<std::tuple<ResultTypes...>> tupleValues(std::size_t reserveSize)
     {
-        using Container = std::vector<std::tuple<ResultType...>>;
+        using Container = std::vector<std::tuple<ResultTypes...>>;
         Container resultValues;
         resultValues.reserve(reserveSize);
 
         while (next())
-           emplaceTupleValues<Container, ResultType...>(resultValues);
+           emplaceTupleValues<Container, ResultTypes...>(resultValues);
 
         reset();
 
         return resultValues;
     }
 
-    template <typename... ResultType,
-              typename... QueryType>
-    std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize, const QueryType&... queryValues)
+    template <typename... ResultTypes,
+              typename... QueryTypes>
+    std::vector<std::tuple<ResultTypes...>> tupleValues(std::size_t reserveSize, const QueryTypes&... queryValues)
     {
-        using Container = std::vector<std::tuple<ResultType...>>;
+        using Container = std::vector<std::tuple<ResultTypes...>>;
         Container resultValues;
         resultValues.reserve(reserveSize);
 
         bindValues(queryValues...);
 
         while (next())
-           emplaceTupleValues<Container, ResultType...>(resultValues);
+           emplaceTupleValues<Container, ResultTypes...>(resultValues);
 
         reset();
 
         return resultValues;
     }
 
-    template <typename... ResultType,
-              typename... ElementType>
-    std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize,
-                                                       const std::vector<std::tuple<ElementType...>> &queryTuples)
+    template <typename... ResultTypes,
+              typename... QueryElementTypes>
+    std::vector<std::tuple<ResultTypes...>> tupleValues(std::size_t reserveSize,
+                                                       const std::vector<std::tuple<QueryElementTypes...>> &queryTuples)
     {
-        using Container = std::vector<std::tuple<ResultType...>>;
+        using Container = std::vector<std::tuple<ResultTypes...>>;
         Container resultValues;
         resultValues.reserve(reserveSize);
 
@@ -163,7 +163,7 @@ protected:
             bindTupleValues(queryTuple);
 
             while (next())
-                emplaceTupleValues<Container, ResultType...>(resultValues);
+                emplaceTupleValues<Container, ResultTypes...>(resultValues);
 
             reset();
         }
@@ -171,12 +171,12 @@ protected:
         return resultValues;
     }
 
-    template <typename... ResultType,
+    template <typename... ResultTypes,
               typename QueryElementType>
-    std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize,
+    std::vector<std::tuple<ResultTypes...>> tupleValues(std::size_t reserveSize,
                                                        const std::vector<QueryElementType> &queryValues)
     {
-        using Container = std::vector<std::tuple<ResultType...>>;
+        using Container = std::vector<std::tuple<ResultTypes...>>;
         Container resultValues;
         resultValues.reserve(reserveSize);
 
@@ -184,7 +184,7 @@ protected:
             bindValues(queryValue);
 
             while (next())
-                emplaceTupleValues<Container, ResultType...>(resultValues);
+                emplaceTupleValues<Container, ResultTypes...>(resultValues);
 
             reset();
         }
@@ -193,7 +193,7 @@ protected:
     }
 
     template <typename ResultType,
-              typename... ResultEntryType>
+              typename... ResultEntryTypes>
     std::vector<ResultType> structValues(std::size_t reserveSize)
     {
         using Container = std::vector<ResultType>;
@@ -201,7 +201,7 @@ protected:
         resultValues.reserve(reserveSize);
 
         while (next())
-           pushBackStructValues<Container, ResultEntryType...>(resultValues);
+           pushBackStructValues<Container, ResultEntryTypes...>(resultValues);
 
         reset();
 
@@ -209,9 +209,9 @@ protected:
     }
 
     template <typename ResultType,
-              typename... ResultEntryType,
-              typename... QueryType>
-    std::vector<ResultType> structValues(std::size_t reserveSize, const QueryType&... queryValues)
+              typename... ResultEntryTypes,
+              typename... QueryTypes>
+    std::vector<ResultType> structValues(std::size_t reserveSize, const QueryTypes&... queryValues)
     {
         using Container = std::vector<ResultType>;
         Container resultValues;
@@ -220,7 +220,7 @@ protected:
         bindValues(queryValues...);
 
         while (next())
-           pushBackStructValues<Container, ResultEntryType...>(resultValues);
+           pushBackStructValues<Container, ResultEntryTypes...>(resultValues);
 
         reset();
 
@@ -228,7 +228,7 @@ protected:
     }
 
     template <typename ResultType,
-              typename... ResultEntryType,
+              typename... ResultEntryTypes,
               typename QueryElementType>
     std::vector<ResultType> structValues(std::size_t reserveSize,
                                          const std::vector<QueryElementType> &queryValues)
@@ -241,7 +241,7 @@ protected:
             bindValues(queryValue);
 
             while (next())
-                pushBackStructValues<Container, ResultEntryType...>(resultValues);
+                pushBackStructValues<Container, ResultEntryTypes...>(resultValues);
 
             reset();
         }
@@ -250,10 +250,10 @@ protected:
     }
 
     template <typename ResultType,
-              typename... ResultEntryType,
-              typename... QueryElementType>
+              typename... ResultEntryTypes,
+              typename... QueryElementTypes>
     std::vector<ResultType> structValues(std::size_t reserveSize,
-                                         const std::vector<std::tuple<QueryElementType...>> &queryTuples)
+                                         const std::vector<std::tuple<QueryElementTypes...>> &queryTuples)
     {
         using Container = std::vector<ResultType>;
         Container resultValues;
@@ -263,7 +263,7 @@ protected:
             bindTupleValues(queryTuple);
 
             while (next())
-                pushBackStructValues<Container, ResultEntryType...>(resultValues);
+                pushBackStructValues<Container, ResultEntryTypes...>(resultValues);
 
             reset();
         }
@@ -272,7 +272,7 @@ protected:
     }
 
     template <typename ResultType,
-              typename... ElementType>
+              typename... ElementTypes>
     std::vector<ResultType> values(std::size_t reserveSize)
     {
         std::vector<ResultType> resultValues;
@@ -327,8 +327,8 @@ protected:
     }
 
     template <typename ResultType,
-              typename... QueryType>
-    std::vector<ResultType> values(std::size_t reserveSize, const QueryType&... queryValues)
+              typename... QueryTypes>
+    std::vector<ResultType> values(std::size_t reserveSize, const QueryTypes&... queryValues)
     {
         std::vector<ResultType> resultValues;
         resultValues.reserve(reserveSize);
@@ -379,74 +379,74 @@ protected:
                              SqliteDatabaseBackend &databaseBackend);
 
 private:
-    template <typename Container,
-              typename... ResultType,
-              int... Index>
-    void emplaceTupleValues(Container &container, std::integer_sequence<int, Index...>)
+    template <typename ContainerType,
+              typename... ResultTypes,
+              int... ColumnIndices>
+    void emplaceTupleValues(ContainerType &container, std::integer_sequence<int, ColumnIndices...>)
     {
-        container.emplace_back(value<ResultType>(Index)...);
+        container.emplace_back(value<ResultTypes>(ColumnIndices)...);
     }
 
-    template <typename Container,
-              typename... ResultType>
-    void emplaceTupleValues(Container &container)
+    template <typename ContainerType,
+              typename... ResultTypes>
+    void emplaceTupleValues(ContainerType &container)
     {
-        emplaceTupleValues<Container, ResultType...>(container, std::make_integer_sequence<int, sizeof...(ResultType)>{});
+        emplaceTupleValues<ContainerType, ResultTypes...>(container, std::make_integer_sequence<int, sizeof...(ResultTypes)>{});
     }
 
-    template <typename Container,
-              typename... ResultEntryType,
-              int... Index>
-    void pushBackStructValues(Container &container, std::integer_sequence<int, Index...>)
+    template <typename ContainerType,
+              typename... ResultEntryTypes,
+              int... ColumnIndices>
+    void pushBackStructValues(ContainerType &container, std::integer_sequence<int, ColumnIndices...>)
     {
-        using ResultType = typename Container::value_type;
-        container.push_back(ResultType{value<ResultEntryType>(Index)...});
+        using ResultType = typename ContainerType::value_type;
+        container.push_back(ResultType{value<ResultEntryTypes>(ColumnIndices)...});
     }
 
-    template <typename Container,
-              typename... ResultEntryType>
-    void pushBackStructValues(Container &container)
+    template <typename ContainerType,
+              typename... ResultEntryTypes>
+    void pushBackStructValues(ContainerType &container)
     {
-        pushBackStructValues<Container, ResultEntryType...>(container, std::make_integer_sequence<int, sizeof...(ResultEntryType)>{});
+        pushBackStructValues<ContainerType, ResultEntryTypes...>(container, std::make_integer_sequence<int, sizeof...(ResultEntryTypes)>{});
     }
 
-    template<typename Type>
-    void bindValuesByIndex(int index, Type value)
+    template<typename ValueType>
+    void bindValuesByIndex(int index, ValueType value)
     {
         bind(index, value);
     }
 
-    template<typename Type, typename... Value>
-    void bindValuesByIndex(int index, Type value, Value... values)
+    template<typename ValueType, typename... ValueTypes>
+    void bindValuesByIndex(int index, ValueType value, ValueTypes... values)
     {
         bind(index, value);
         bindValuesByIndex(index + 1, values...);
     }
 
-    template<typename Type>
-    void bindValuesByName(Utils::SmallStringView name, Type value)
+    template<typename ValueType>
+    void bindValuesByName(Utils::SmallStringView name, ValueType value)
     {
        bind(bindingIndexForName(name), value);
     }
 
-    template<typename Type, typename... Values>
-    void bindValuesByName(Utils::SmallStringView name, Type value, Values... values)
+    template<typename ValueType, typename... ValueTypes>
+    void bindValuesByName(Utils::SmallStringView name, ValueType value, ValueTypes... values)
     {
        bind(bindingIndexForName(name), value);
        bindValuesByName(values...);
     }
 
-    template <typename TupleType, std::size_t... Index>
-    void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<Index...>)
+    template <typename TupleType, std::size_t... ColumnIndices>
+    void bindTupleValuesElement(const TupleType &tuple, std::index_sequence<ColumnIndices...>)
     {
-        bindValues(std::get<Index>(tuple)...);
+        bindValues(std::get<ColumnIndices>(tuple)...);
     }
 
     template <typename TupleType,
-              typename Indices = std::make_index_sequence<std::tuple_size<TupleType>::value>>
+              typename ColumnIndices = std::make_index_sequence<std::tuple_size<TupleType>::value>>
     void bindTupleValues(const TupleType &element)
     {
-        bindTupleValuesElement(element, Indices());
+        bindTupleValuesElement(element, ColumnIndices());
     }
 
 private:
diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h
index 194616b2b44..3798cb6e4e8 100644
--- a/src/libs/utils/smallstringview.h
+++ b/src/libs/utils/smallstringview.h
@@ -140,6 +140,8 @@ public:
         return m_pointer[0] == characterToSearch;
     }
 
+
+
 private:
     const char *m_pointer;
     size_type m_size;
diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
index a8eb4ce09a1..5622179272b 100644
--- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
+++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
@@ -50,7 +50,7 @@ using ClangBackEnd::PchGenerator;
 using ClangBackEnd::PchManagerClientProxy;
 using ClangBackEnd::PchManagerServer;
 using ClangBackEnd::ProjectParts;
-using ClangBackEnd::StringCache;
+using ClangBackEnd::FilePathCache;
 
 class ApplicationEnvironment : public ClangBackEnd::Environment
 {
@@ -103,7 +103,7 @@ int main(int argc, char *argv[])
 
     const QString connection =  processArguments(application);
 
-    StringCache<Utils::PathString> filePathCache;
+    FilePathCache<> filePathCache;
     ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher(filePathCache);
     ApplicationEnvironment environment;
     PchGenerator<QProcess> pchGenerator(environment);
diff --git a/src/tools/clangpchmanagerbackend/source/clangpathwatcher.h b/src/tools/clangpchmanagerbackend/source/clangpathwatcher.h
index a02d09f3f7f..10dbbb12471 100644
--- a/src/tools/clangpchmanagerbackend/source/clangpathwatcher.h
+++ b/src/tools/clangpchmanagerbackend/source/clangpathwatcher.h
@@ -37,8 +37,8 @@ namespace ClangBackEnd {
 class WatcherEntry
 {
 public:
-    uint id;
-    uint path;
+    FilePathIndex id;
+    FilePathIndex path;
 
     friend bool operator==(const WatcherEntry &first, const WatcherEntry &second)
     {
@@ -50,12 +50,12 @@ public:
         return std::tie(first.path, first.id) < std::tie(second.path, second.id);
     }
 
-    friend bool operator<(const WatcherEntry &entry, uint path)
+    friend bool operator<(const WatcherEntry &entry, FilePathIndex path)
     {
         return entry.path < path;
     }
 
-    friend bool operator<(uint path, const WatcherEntry &entry)
+    friend bool operator<(FilePathIndex path, const WatcherEntry &entry)
     {
         return path < entry.path;
     }
@@ -63,12 +63,14 @@ public:
 
 using WatcherEntries = std::vector<WatcherEntry>;
 
+using IdCache = StringCache<Utils::SmallString, FilePathIndex, NonLockingMutex>;
+
 template <typename FileSystemWatcher,
           typename Timer>
 class ClangPathWatcher : public ClangPathWatcherInterface
 {
 public:
-    ClangPathWatcher(StringCache<Utils::PathString> &pathCache,
+    ClangPathWatcher(FilePathCache<> &pathCache,
                      ClangPathWatcherNotifier *notifier=nullptr)
         : m_pathCache(pathCache),
           m_notifier(notifier)
@@ -130,9 +132,9 @@ unittest_public:
         return ids;
     }
 
-    std::vector<uint> convertToIdNumbers(const Utils::SmallStringVector &ids)
+    std::vector<FilePathIndex> convertToIdNumbers(const Utils::SmallStringVector &ids)
     {
-        std::vector<uint> idNumbers = m_idCache.stringIds(ids);
+        std::vector<FilePathIndex> idNumbers = m_idCache.stringIds(ids);
 
         std::sort(idNumbers.begin(), idNumbers.end());
 
@@ -149,19 +151,19 @@ unittest_public:
     }
 
 
-    std::pair<WatcherEntries,std::vector<uint>>
+    std::pair<WatcherEntries,std::vector<FilePathIndex>>
     convertIdPathsToWatcherEntriesAndIds(const std::vector<IdPaths> &idPaths)
     {
         WatcherEntries entries;
         entries.reserve(sizeOfIdPaths(idPaths));
-        std::vector<uint> ids;
+        std::vector<FilePathIndex> ids;
         ids.reserve(ids.size());
 
         auto outputIterator = std::back_inserter(entries);
 
         for (const IdPaths &idPath : idPaths)
         {
-            uint id = m_idCache.stringId(idPath.id);
+            FilePathIndex id = m_idCache.stringId(idPath.id);
 
             ids.push_back(id);
 
@@ -190,7 +192,7 @@ unittest_public:
     }
 
     void removeUnusedEntries(const WatcherEntries &entries,
-                             const std::vector<uint> &ids)
+                             const std::vector<FilePathIndex> &ids)
     {
         auto oldEntries = notAnymoreWatchedEntriesWithIds(entries, ids);
 
@@ -272,7 +274,7 @@ unittest_public:
 
     WatcherEntries notAnymoreWatchedEntriesWithIds(
             const WatcherEntries &newEntries,
-            const std::vector<uint> &ids) const
+            const std::vector<FilePathIndex> &ids) const
     {
         auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less<WatcherEntry>());
 
@@ -328,7 +330,7 @@ unittest_public:
         return m_watchedEntries;
     }
 
-    WatcherEntries removeIdsFromWatchedEntries(const std::vector<uint> &ids)
+    WatcherEntries removeIdsFromWatchedEntries(const std::vector<FilePathIndex> &ids)
     {
 
         auto keep = [&] (const WatcherEntry &entry) {
@@ -368,7 +370,7 @@ unittest_public:
 
     WatcherEntries watchedEntriesForPaths(Utils::PathStringVector &&filePaths)
     {
-        std::vector<uint> pathIds = m_pathCache.stringIds(filePaths);
+        std::vector<FilePathIndex> pathIds = m_pathCache.stringIds(filePaths);
 
         WatcherEntries foundEntries;
 
@@ -414,22 +416,22 @@ unittest_public:
         }
     }
 
-    StringCache<Utils::PathString> &pathCache()
+    FilePathCache<> &pathCache()
     {
         return m_pathCache;
     }
 
-    StringCache<Utils::SmallString> &idCache()
+    IdCache &idCache()
     {
         return m_idCache;
     }
 
 private:
-    StringCache<Utils::SmallString> m_idCache;
+    IdCache m_idCache;
     WatcherEntries m_watchedEntries;
     ChangedFilePathCompressor<Timer> m_changedFilePathCompressor;
     FileSystemWatcher m_fileSystemWatcher;
-    StringCache<Utils::PathString> &m_pathCache;
+    FilePathCache<> &m_pathCache;
     ClangPathWatcherNotifier *m_notifier;
 };
 
diff --git a/src/tools/clangpchmanagerbackend/source/collectincludesaction.h b/src/tools/clangpchmanagerbackend/source/collectincludesaction.h
index 5b8b8ad5e6b..339d491848d 100644
--- a/src/tools/clangpchmanagerbackend/source/collectincludesaction.h
+++ b/src/tools/clangpchmanagerbackend/source/collectincludesaction.h
@@ -38,10 +38,10 @@ namespace ClangBackEnd {
 class CollectIncludesAction final : public clang::PreprocessOnlyAction
 {
 public:
-    CollectIncludesAction(std::vector<uint> &includeIds,
-                          StringCache<Utils::PathString> &filePathCache,
-                          std::vector<uint> &excludedIncludeUID,
-                          std::vector<uint> &alreadyIncludedFileUIDs)
+    CollectIncludesAction(FilePathIndices &includeIds,
+                          FilePathCache<> &filePathCache,
+                          FilePathIndices &excludedIncludeUID,
+                          FilePathIndices &alreadyIncludedFileUIDs)
         : m_includeIds(includeIds),
           m_filePathCache(filePathCache),
           m_excludedIncludeUID(excludedIncludeUID),
@@ -78,10 +78,10 @@ public:
     }
 
 private:
-    std::vector<uint> &m_includeIds;
-    StringCache<Utils::PathString> &m_filePathCache;
-    std::vector<uint> &m_excludedIncludeUID;
-    std::vector<uint> &m_alreadyIncludedFileUIDs;
+    FilePathIndices &m_includeIds;
+    FilePathCache<> &m_filePathCache;
+    FilePathIndices &m_excludedIncludeUID;
+    FilePathIndices &m_alreadyIncludedFileUIDs;
 };
 
 } // namespace ClangBackEnd
diff --git a/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h
index ba86822fce3..a57d72adfcb 100644
--- a/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h
+++ b/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h
@@ -47,10 +47,10 @@ class CollectIncludesPreprocessorCallbacks final : public clang::PPCallbacks
 {
 public:
     CollectIncludesPreprocessorCallbacks(clang::HeaderSearch &headerSearch,
-                                         std::vector<uint> &includeIds,
-                                         StringCache<Utils::PathString> &filePathCache,
-                                         const std::vector<uint> &excludedIncludeUID,
-                                         std::vector<uint>  &alreadyIncludedFileUIDs)
+                                         std::vector<FilePathIndex> &includeIds,
+                                         FilePathCache<> &filePathCache,
+                                         const std::vector<FilePathIndex> &excludedIncludeUID,
+                                         std::vector<FilePathIndex>  &alreadyIncludedFileUIDs)
         : m_headerSearch(headerSearch),
           m_includeIds(includeIds),
           m_filePathCache(filePathCache),
@@ -78,7 +78,7 @@ public:
                     m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, fileUID);
                     Utils::PathString filePath = filePathFromFile(file);
                     if (!filePath.isEmpty()) {
-                        uint includeId = m_filePathCache.stringId(filePath);
+                        FilePathIndex includeId = m_filePathCache.stringId(filePath);
                         m_includeIds.emplace_back(includeId);
                     }
                 }
@@ -132,7 +132,7 @@ public:
                                    uid);
     }
 
-    std::pair<bool, std::vector<uint>::iterator> isNotAlreadyIncluded(uint uid) const
+    std::pair<bool, std::vector<FilePathIndex>::iterator> isNotAlreadyIncluded(FilePathIndex uid) const
     {
         auto range = std::equal_range(m_alreadyIncludedFileUIDs.begin(),
                                       m_alreadyIncludedFileUIDs.end(),
@@ -174,10 +174,10 @@ public:
 
 private:
     clang::HeaderSearch &m_headerSearch;
-    std::vector<uint> &m_includeIds;
-    StringCache<Utils::PathString> &m_filePathCache;
-    const std::vector<uint> &m_excludedIncludeUID;
-    std::vector<uint> &m_alreadyIncludedFileUIDs;
+    std::vector<FilePathIndex> &m_includeIds;
+    FilePathCache<> &m_filePathCache;
+    const std::vector<FilePathIndex> &m_excludedIncludeUID;
+    std::vector<FilePathIndex> &m_alreadyIncludedFileUIDs;
     bool m_skipInclude = false;
 };
 
diff --git a/src/tools/clangpchmanagerbackend/source/collectincludestoolaction.h b/src/tools/clangpchmanagerbackend/source/collectincludestoolaction.h
index 87e92c1df3e..42b8a62cea7 100644
--- a/src/tools/clangpchmanagerbackend/source/collectincludestoolaction.h
+++ b/src/tools/clangpchmanagerbackend/source/collectincludestoolaction.h
@@ -36,8 +36,8 @@ namespace ClangBackEnd {
 class CollectIncludesToolAction final : public clang::tooling::FrontendActionFactory
 {
 public:
-    CollectIncludesToolAction(std::vector<uint> &includeIds,
-                              StringCache<Utils::PathString> &filePathCache,
+    CollectIncludesToolAction(std::vector<FilePathIndex> &includeIds,
+                              FilePathCache<> &filePathCache,
                               const Utils::PathStringVector &excludedIncludes)
         : m_includeIds(includeIds),
           m_filePathCache(filePathCache),
@@ -72,9 +72,9 @@ public:
                                          m_alreadyIncludedFileUIDs);
     }
 
-    std::vector<uint> generateExcludedIncludeFileUIDs(clang::FileManager &fileManager) const
+    std::vector<FilePathIndex> generateExcludedIncludeFileUIDs(clang::FileManager &fileManager) const
     {
-        std::vector<uint> fileUIDs;
+        std::vector<FilePathIndex> fileUIDs;
         fileUIDs.reserve(m_excludedIncludes.size());
 
         for (const Utils::PathString &filePath : m_excludedIncludes) {
@@ -90,10 +90,10 @@ public:
     }
 
 private:
-    std::vector<uint> m_alreadyIncludedFileUIDs;
-    std::vector<uint> m_excludedIncludeUIDs;
-    std::vector<uint> &m_includeIds;
-    StringCache<Utils::PathString> &m_filePathCache;
+    std::vector<FilePathIndex> m_alreadyIncludedFileUIDs;
+    std::vector<FilePathIndex> m_excludedIncludeUIDs;
+    std::vector<FilePathIndex> &m_includeIds;
+    FilePathCache<> &m_filePathCache;
     const Utils::PathStringVector &m_excludedIncludes;
 };
 
diff --git a/src/tools/clangpchmanagerbackend/source/idpaths.h b/src/tools/clangpchmanagerbackend/source/idpaths.h
index f6f312f05fd..a407e24530f 100644
--- a/src/tools/clangpchmanagerbackend/source/idpaths.h
+++ b/src/tools/clangpchmanagerbackend/source/idpaths.h
@@ -29,13 +29,15 @@
 
 #include <iosfwd>
 
+#include <stringcachefwd.h>
+
 namespace ClangBackEnd {
 
 class IdPaths
 {
 public:
     Utils::SmallString id;
-    std::vector<uint> paths;
+    std::vector<FilePathIndex> paths;
 
     friend bool operator==(const IdPaths &first, const IdPaths &second)
     {
diff --git a/src/tools/clangpchmanagerbackend/source/includecollector.cpp b/src/tools/clangpchmanagerbackend/source/includecollector.cpp
index b380fa2b8b6..421123b3a7c 100644
--- a/src/tools/clangpchmanagerbackend/source/includecollector.cpp
+++ b/src/tools/clangpchmanagerbackend/source/includecollector.cpp
@@ -33,7 +33,7 @@
 
 namespace ClangBackEnd {
 
-IncludeCollector::IncludeCollector(StringCache<Utils::PathString> &filePathCache)
+IncludeCollector::IncludeCollector(FilePathCache<> &filePathCache)
     :  m_filePathCache(filePathCache)
 {
 }
@@ -69,7 +69,7 @@ void IncludeCollector::setExcludedIncludes(Utils::PathStringVector &&excludedInc
 #endif
 }
 
-std::vector<uint> IncludeCollector::takeIncludeIds()
+std::vector<FilePathIndex> IncludeCollector::takeIncludeIds()
 {
     std::sort(m_includeIds.begin(), m_includeIds.end());
 
diff --git a/src/tools/clangpchmanagerbackend/source/includecollector.h b/src/tools/clangpchmanagerbackend/source/includecollector.h
index ba485ea33d7..73f9b948afa 100644
--- a/src/tools/clangpchmanagerbackend/source/includecollector.h
+++ b/src/tools/clangpchmanagerbackend/source/includecollector.h
@@ -34,19 +34,19 @@ namespace ClangBackEnd {
 class IncludeCollector : public ClangTool
 {
 public:
-    IncludeCollector(StringCache<Utils::PathString> &filePathCache);
+    IncludeCollector(FilePathCache<> &filePathCache);
 
     void collectIncludes();
 
     void setExcludedIncludes(Utils::PathStringVector &&excludedIncludes);
 
-    std::vector<uint> takeIncludeIds();
+    std::vector<FilePathIndex> takeIncludeIds();
 
 private:
     Utils::PathStringVector m_excludedIncludes;
-    std::vector<uint> m_includeIds;
+    std::vector<FilePathIndex> m_includeIds;
     Utils::SmallStringVector m_directories;
-    StringCache<Utils::PathString> &m_filePathCache;
+    FilePathCache<> &m_filePathCache;
 };
 
 } // namespace ClangBackEnd
diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp
index 4c685dc34e1..d8551d77677 100644
--- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp
+++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp
@@ -37,7 +37,7 @@
 
 namespace ClangBackEnd {
 
-PchCreator::PchCreator(Environment &environment, StringCache<Utils::PathString> &filePathCache)
+PchCreator::PchCreator(Environment &environment, FilePathCache<> &filePathCache)
    : m_environment(environment),
      m_filePathCache(filePathCache)
 {
@@ -45,7 +45,7 @@ PchCreator::PchCreator(Environment &environment, StringCache<Utils::PathString>
 
 PchCreator::PchCreator(V2::ProjectPartContainers &&projectsParts,
                        Environment &environment,
-                       StringCache<Utils::PathString> &filePathCache,
+                       FilePathCache<> &filePathCache,
                        PchGeneratorInterface *pchGenerator,
                        V2::FileContainers &&generatedFiles)
     : m_projectParts(std::move(projectsParts)),
@@ -239,7 +239,7 @@ Utils::SmallStringVector PchCreator::generateGlobalClangCompilerArguments() cons
     return compilerArguments;
 }
 
-std::vector<uint> PchCreator::generateGlobalPchIncludeIds() const
+std::vector<FilePathIndex> PchCreator::generateGlobalPchIncludeIds() const
 {
     IncludeCollector collector(m_filePathCache);
 
@@ -267,7 +267,7 @@ std::size_t contentSize(const std::vector<Utils::PathString> &includes)
 }
 
 Utils::SmallString PchCreator::generatePchIncludeFileContent(
-        const std::vector<uint> &includeIds) const
+        const std::vector<FilePathIndex> &includeIds) const
 {
     Utils::SmallString fileContent;
     const std::size_t lineTemplateSize = 12;
@@ -461,7 +461,7 @@ Utils::PathStringVector PchCreator::generateProjectPartHeaderAndSourcePaths(
     return includeAndSources;
 }
 
-std::vector<uint> PchCreator::generateProjectPartPchIncludes(
+std::vector<FilePathIndex> PchCreator::generateProjectPartPchIncludes(
         const V2::ProjectPartContainer &projectPart) const
 {
     Utils::SmallString jointedFileContent = generateProjectPartHeaderAndSourcesContent(projectPart);
diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.h b/src/tools/clangpchmanagerbackend/source/pchcreator.h
index 1b418ad3db2..5548ec7acd2 100644
--- a/src/tools/clangpchmanagerbackend/source/pchcreator.h
+++ b/src/tools/clangpchmanagerbackend/source/pchcreator.h
@@ -48,10 +48,10 @@ class PchCreator final : public PchCreatorInterface
 {
 public:
     PchCreator(Environment &environment,
-               StringCache<Utils::PathString> &filePathCache);
+               FilePathCache<> &filePathCache);
     PchCreator(V2::ProjectPartContainers &&projectsParts,
                Environment &environment,
-               StringCache<Utils::PathString> &filePathCache,
+               FilePathCache<> &filePathCache,
                PchGeneratorInterface *pchGenerator,
                V2::FileContainers &&generatedFiles);
 
@@ -70,9 +70,9 @@ unittest_public:
     Utils::SmallStringVector generateGlobalPchCompilerArguments() const;
     Utils::SmallStringVector generateGlobalClangCompilerArguments() const;
 
-    std::vector<uint> generateGlobalPchIncludeIds() const;
+    std::vector<FilePathIndex> generateGlobalPchIncludeIds() const;
 
-    Utils::SmallString generatePchIncludeFileContent(const std::vector<uint> &includeIds) const;
+    Utils::SmallString generatePchIncludeFileContent(const std::vector<FilePathIndex> &includeIds) const;
     Utils::SmallString generateGlobalPchHeaderFileContent() const;
     std::unique_ptr<QFile> generateGlobalPchHeaderFile();
     void generatePch(Utils::SmallStringVector &&commandLineArguments,
@@ -97,7 +97,7 @@ unittest_public:
             const V2::ProjectPartContainer &projectPart);
     static Utils::PathStringVector generateProjectPartHeaderAndSourcePaths(
             const V2::ProjectPartContainer &projectPart);
-    std::vector<uint> generateProjectPartPchIncludes(
+    std::vector<FilePathIndex> generateProjectPartPchIncludes(
             const V2::ProjectPartContainer &projectPart) const;
     Utils::SmallString generateProjectPathPchHeaderFilePath(
             const V2::ProjectPartContainer &projectPart) const;
@@ -127,7 +127,7 @@ private:
     std::vector<ProjectPartPch> m_projectPartPchs;
     std::vector<IdPaths> m_projectsIncludeIds;
     Environment &m_environment;
-    StringCache<Utils::PathString> &m_filePathCache;
+    FilePathCache<> &m_filePathCache;
     PchGeneratorInterface *m_pchGenerator = nullptr;
 };
 
diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp
index f22458c8b3d..03261ae164c 100644
--- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp
+++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp
@@ -36,7 +36,7 @@
 
 namespace ClangBackEnd {
 
-PchManagerServer::PchManagerServer(StringCache<Utils::PathString> &filePathCache,
+PchManagerServer::PchManagerServer(FilePathCache<> &filePathCache,
                                    ClangPathWatcherInterface &fileSystemWatcher,
                                    PchCreatorInterface &pchCreator,
                                    ProjectPartsInterface &projectParts)
diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h
index b9df33f8b9f..7be9c759669 100644
--- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h
+++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h
@@ -46,7 +46,7 @@ class PchManagerServer : public PchManagerServerInterface,
 
 {
 public:
-    PchManagerServer(StringCache<Utils::PathString> &filePathCache,
+    PchManagerServer(FilePathCache<> &filePathCache,
                      ClangPathWatcherInterface &fileSystemWatcher,
                      PchCreatorInterface &pchCreator,
                      ProjectPartsInterface &projectParts);
@@ -60,7 +60,7 @@ public:
     void taskFinished(TaskFinishStatus status, const ProjectPartPch &projectPartPch) override;
 
 private:
-    StringCache<Utils::PathString> &m_filePathCache;
+    FilePathCache<> &m_filePathCache;
     ClangPathWatcherInterface &m_fileSystemWatcher;
     PchCreatorInterface &m_pchCreator;
     ProjectPartsInterface &m_projectParts;
diff --git a/src/tools/clangrefactoringbackend/source/clangquery.cpp b/src/tools/clangrefactoringbackend/source/clangquery.cpp
index b625e9e197f..620a7ebaab0 100644
--- a/src/tools/clangrefactoringbackend/source/clangquery.cpp
+++ b/src/tools/clangrefactoringbackend/source/clangquery.cpp
@@ -54,7 +54,7 @@ struct CollectBoundNodes : MatchFinder::MatchCallback {
   }
 };
 
-ClangQuery::ClangQuery(StringCache<Utils::PathString, std::mutex> &filePathCache,
+ClangQuery::ClangQuery(FilePathCache<std::mutex> &filePathCache,
                        Utils::SmallString &&query)
     : query(std::move(query)),
       filePathCache(filePathCache)
diff --git a/src/tools/clangrefactoringbackend/source/clangquery.h b/src/tools/clangrefactoringbackend/source/clangquery.h
index faa5821ca3b..7d99766008d 100644
--- a/src/tools/clangrefactoringbackend/source/clangquery.h
+++ b/src/tools/clangrefactoringbackend/source/clangquery.h
@@ -51,7 +51,7 @@ namespace ClangBackEnd {
 class ClangQuery : public ClangTool
 {
 public:
-    ClangQuery(StringCache<Utils::PathString, std::mutex> &filePathCache, Utils::SmallString &&query={});
+    ClangQuery(FilePathCache<std::mutex> &filePathCache, Utils::SmallString &&query={});
 
     void setQuery(Utils::SmallString &&query);
 
@@ -69,7 +69,7 @@ private:
     SourceRangesContainer sourceRangesContainer;
     Utils::SmallString query;
     std::vector<DynamicASTMatcherDiagnosticContainer> diagnosticContainers_;
-    StringCache<Utils::PathString, std::mutex> &filePathCache;
+    FilePathCache<std::mutex> &filePathCache;
 };
 
 } // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp b/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp
index 32c8e8694e2..692065a9e79 100644
--- a/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp
+++ b/src/tools/clangrefactoringbackend/source/clangquerygatherer.cpp
@@ -29,7 +29,7 @@
 
 namespace ClangBackEnd {
 
-ClangQueryGatherer::ClangQueryGatherer(StringCache<Utils::PathString, std::mutex> *filePathCache,
+ClangQueryGatherer::ClangQueryGatherer(FilePathCache<std::mutex> *filePathCache,
                                        std::vector<V2::FileContainer> &&sources,
                                        std::vector<V2::FileContainer> &&unsaved,
                                        Utils::SmallString &&query)
@@ -43,7 +43,7 @@ ClangQueryGatherer::ClangQueryGatherer(StringCache<Utils::PathString, std::mutex
 
 SourceRangesForQueryMessage
 ClangQueryGatherer::createSourceRangesForSource(
-        StringCache<Utils::PathString, std::mutex> *filePathCache,
+        FilePathCache<std::mutex> *filePathCache,
         V2::FileContainer &&source,
         const std::vector<V2::FileContainer> &unsaved,
         Utils::SmallString &&query)
diff --git a/src/tools/clangrefactoringbackend/source/clangquerygatherer.h b/src/tools/clangrefactoringbackend/source/clangquerygatherer.h
index 7d93560eecf..c1fd6341fab 100644
--- a/src/tools/clangrefactoringbackend/source/clangquerygatherer.h
+++ b/src/tools/clangrefactoringbackend/source/clangquerygatherer.h
@@ -41,13 +41,13 @@ public:
     using Future = std::future<SourceRangesForQueryMessage>;
 
     ClangQueryGatherer() = default;
-    ClangQueryGatherer(StringCache<Utils::PathString, std::mutex> *filePathCache,
+    ClangQueryGatherer(FilePathCache<std::mutex> *filePathCache,
                        std::vector<V2::FileContainer> &&sources,
                        std::vector<V2::FileContainer> &&unsaved,
                        Utils::SmallString &&query);
 
     static SourceRangesForQueryMessage createSourceRangesForSource(
-            StringCache<Utils::PathString, std::mutex> *filePathCache,
+            FilePathCache<std::mutex> *filePathCache,
             V2::FileContainer &&source,
             const std::vector<V2::FileContainer> &unsaved,
             Utils::SmallString &&query);
@@ -69,7 +69,7 @@ protected:
     std::vector<Future> finishedFutures();
 
 private:
-    StringCache<Utils::PathString, std::mutex> *m_filePathCache = nullptr;
+    FilePathCache<std::mutex> *m_filePathCache = nullptr;
     SourceRangeFilter m_sourceRangeFilter;
     std::vector<V2::FileContainer> m_sources;
     std::vector<V2::FileContainer> m_unsaved;
diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
index d8e81a9044f..a342ff8478b 100644
--- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
+++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
@@ -12,7 +12,9 @@ HEADERS += \
     $$PWD/collectsymbolsastvisitor.h \
     $$PWD/sourcelocationentry.h \
     $$PWD/symbolscollectorinterface.h \
-    $$PWD/symbolstorageinterface.h
+    $$PWD/symbolstorageinterface.h \
+    $$PWD/symbolstorage.h \
+    $$PWD/storagesqlitestatementfactory.h
 
 !isEmpty(LIBTOOLING_LIBS) {
 SOURCES += \
@@ -52,4 +54,5 @@ SOURCES += \
     $$PWD/collectsymbolsaction.cpp \
     $$PWD/collectmacrossourcefilecallbacks.cpp \
     $$PWD/symbolentry.cpp \
-    $$PWD/sourcelocationentry.cpp
+    $$PWD/sourcelocationentry.cpp \
+    $$PWD/symbolstorage.cpp
diff --git a/src/tools/clangrefactoringbackend/source/collectsymbolsastvisitor.h b/src/tools/clangrefactoringbackend/source/collectsymbolsastvisitor.h
index 11fd41900fd..73fe3c5b138 100644
--- a/src/tools/clangrefactoringbackend/source/collectsymbolsastvisitor.h
+++ b/src/tools/clangrefactoringbackend/source/collectsymbolsastvisitor.h
@@ -60,7 +60,7 @@ public:
 
     bool VisitNamedDecl(const clang::NamedDecl *declaration)
     {
-        auto globalId = declaration->getCanonicalDecl()->getLocation().getRawEncoding();
+        SymbolIndex globalId = toSymbolIndex(declaration->getCanonicalDecl());
         auto sourceLocation = declaration->getLocation();
 
         auto found = m_symbolEntries.find(globalId);
@@ -81,7 +81,7 @@ public:
     bool VisitDeclRefExpr(const clang::DeclRefExpr *expression)
     {
         auto declaration = expression->getFoundDecl();
-        auto globalId = declaration->getCanonicalDecl()->getLocation().getRawEncoding();
+        SymbolIndex globalId = toSymbolIndex(declaration->getCanonicalDecl());
         auto sourceLocation = expression->getLocation();
 
         m_sourceLocationEntries.emplace_back(globalId,
@@ -92,7 +92,7 @@ public:
         return true;
     }
 
-    uint filePathId(clang::SourceLocation sourceLocation)
+    FilePathIndex filePathId(clang::SourceLocation sourceLocation)
     {
        auto filePath = m_sourceManager.getFilename(sourceLocation);
 
@@ -114,6 +114,11 @@ public:
         return usr;
     }
 
+    static SymbolIndex toSymbolIndex(const void *pointer)
+    {
+        return SymbolIndex(reinterpret_cast<std::uintptr_t>(pointer));
+    }
+
 private:
     SymbolEntries &m_symbolEntries;
     SourceLocationEntries &m_sourceLocationEntries;
diff --git a/src/tools/clangrefactoringbackend/source/refactoringserver.h b/src/tools/clangrefactoringbackend/source/refactoringserver.h
index d988ea5b806..33eaee2a0a4 100644
--- a/src/tools/clangrefactoringbackend/source/refactoringserver.h
+++ b/src/tools/clangrefactoringbackend/source/refactoringserver.h
@@ -75,7 +75,7 @@ private:
                                                           Utils::SmallString &&query);
 
 private:
-    StringCache<Utils::PathString, std::mutex> m_filePathCache;
+    FilePathCache<std::mutex> m_filePathCache;
     ClangQueryGatherer m_gatherer;
     QTimer m_pollTimer;
 };
diff --git a/src/tools/clangrefactoringbackend/source/sourcelocationentry.h b/src/tools/clangrefactoringbackend/source/sourcelocationentry.h
index 20f506c8b1f..dbe70123883 100644
--- a/src/tools/clangrefactoringbackend/source/sourcelocationentry.h
+++ b/src/tools/clangrefactoringbackend/source/sourcelocationentry.h
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#include <stringcachefwd.h>
+
 #include <limits>
 #include <vector>
 #include <iosfwd>
@@ -51,11 +53,13 @@ public:
     uint column = 0;
 };
 
+using SymbolIndex = long long;
+
 class SourceLocationEntry
 {
 public:
-    SourceLocationEntry(uint symbolId,
-                        uint fileId,
+    SourceLocationEntry(SymbolIndex symbolId,
+                        FilePathIndex fileId,
                         LineColumn lineColumn,
                         SymbolType symbolType)
         : symbolId(symbolId),
@@ -65,8 +69,8 @@ public:
           symbolType(symbolType)
     {}
 
-    uint symbolId = 0;
-    uint fileId = std::numeric_limits<uint>::max();
+    SymbolIndex symbolId = 0;
+    FilePathIndex fileId = std::numeric_limits<uint>::max();
     uint line =  0;
     uint column = 0;
     SymbolType symbolType;
diff --git a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp
index e83f6a3c383..6d9d4982273 100644
--- a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp
+++ b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.cpp
@@ -54,7 +54,7 @@ namespace ClangBackEnd {
 SourceRangeExtractor::SourceRangeExtractor(
         const clang::SourceManager &sourceManager,
         const clang::LangOptions &languageOptions,
-        ClangBackEnd::StringCache<Utils::PathString, std::mutex> &filePathCache,
+        ClangBackEnd::FilePathCache<std::mutex> &filePathCache,
         SourceRangesContainer &sourceRangesContainer)
     : sourceManager(sourceManager),
       languageOptions(languageOptions),
@@ -145,7 +145,7 @@ void SourceRangeExtractor::insertSourceRange(uint fileId,
                                             std::move(lineSnippet));
 }
 
-uint SourceRangeExtractor::findFileId(clang::FileID fileId, const clang::FileEntry *fileEntry) const
+FilePathIndex SourceRangeExtractor::findFileId(clang::FileID fileId, const clang::FileEntry *fileEntry) const
 {
     auto found = m_fileIdMapping.find(fileId.getHashValue());
     if (found != m_fileIdMapping.end()) {
diff --git a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h
index 7a07e5c3f87..30646429747 100644
--- a/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h
+++ b/src/tools/clangrefactoringbackend/source/sourcerangeextractor.h
@@ -59,7 +59,7 @@ class SourceRangeExtractor
 public:
     SourceRangeExtractor(const clang::SourceManager &sourceManager,
                          const clang::LangOptions &languageOptions,
-                         ClangBackEnd::StringCache<Utils::PathString, std::mutex> &filePathCache,
+                         ClangBackEnd::FilePathCache<std::mutex> &filePathCache,
                          SourceRangesContainer &sourceRangesContainer);
 
     void addSourceRange(const clang::SourceRange &sourceRange);
@@ -82,13 +82,13 @@ private:
                            uint endOffset,
                            Utils::SmallString &&lineSnippet);
 
-    uint findFileId(clang::FileID fileId, const clang::FileEntry *fileEntry) const;
+    FilePathIndex findFileId(clang::FileID fileId, const clang::FileEntry *fileEntry) const;
 
 private:
     mutable std::unordered_map<uint, uint> m_fileIdMapping;
     const clang::SourceManager &sourceManager;
     const clang::LangOptions &languageOptions;
-    ClangBackEnd::StringCache<Utils::PathString, std::mutex> &filePathCache;
+    ClangBackEnd::FilePathCache<std::mutex> &filePathCache;
     SourceRangesContainer &sourceRangesContainer;
 };
 
diff --git a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h
new file mode 100644
index 00000000000..22bd7cf5f5c
--- /dev/null
+++ b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <createtablesqlstatementbuilder.h>
+
+#include <sqlitetransaction.h>
+#include <sqlitetable.h>
+
+namespace ClangBackEnd {
+
+template<typename Database,
+         typename ReadStatement,
+         typename WriteStatement>
+class StorageSqliteStatementFactory
+{
+public:
+    using DatabaseType = Database;
+    using ReadStatementType = ReadStatement;
+    using WriteStatementType = WriteStatement;
+
+    StorageSqliteStatementFactory(Database &database)
+        : database(database)
+    {
+    }
+
+    Sqlite::SqliteTable createSymbolsTable()
+    {
+        Sqlite::SqliteTable table;
+        table.setUseIfNotExists(true);
+        table.setName("symbols");
+        table.addColumn("symbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
+        table.addColumn("usr", Sqlite::ColumnType::Text);
+        table.addColumn("symbolName", Sqlite::ColumnType::Text);
+
+        Sqlite::SqliteImmediateTransaction<DatabaseType> transaction(database);
+        table.initialize(database);
+        transaction.commit();
+
+        return table;
+    }
+
+    Sqlite::SqliteTable createLocationsTable()
+    {
+        Sqlite::SqliteTable table;
+        table.setUseIfNotExists(true);
+        table.setName("locations");
+        table.addColumn("symbolId", Sqlite::ColumnType::Integer);
+        table.addColumn("line", Sqlite::ColumnType::Integer);
+        table.addColumn("column", Sqlite::ColumnType::Integer);
+        table.addColumn("sourceId", Sqlite::ColumnType::Integer);
+
+        Sqlite::SqliteImmediateTransaction<DatabaseType> transaction(database);
+        table.initialize(database);
+        transaction.commit();
+
+        return table;
+    }
+
+    Sqlite::SqliteTable createSourcesTable()
+    {
+        Sqlite::SqliteTable table;
+        table.setUseIfNotExists(true);
+        table.setName("sources");
+        table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
+        table.addColumn("sourcePath", Sqlite::ColumnType::Text);
+
+        Sqlite::SqliteImmediateTransaction<DatabaseType> transaction(database);
+        table.initialize(database);
+        transaction.commit();
+
+        return table;
+    }
+
+    Sqlite::SqliteTable createNewSymbolsTable() const
+    {
+        Sqlite::SqliteTable table;
+        table.setName("newSymbols");
+        table.setUseTemporaryTable(true);
+        table.addColumn("temporarySymbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
+        table.addColumn("symbolId", Sqlite::ColumnType::Integer);
+        table.addColumn("usr", Sqlite::ColumnType::Text);
+        table.addColumn("symbolName", Sqlite::ColumnType::Text);
+
+        Sqlite::SqliteImmediateTransaction<DatabaseType> transaction(database);
+        table.initialize(database);
+        transaction.commit();
+
+        return table;
+    }
+
+    Sqlite::SqliteTable createNewLocationsTable() const
+    {
+        Sqlite::SqliteTable table;
+        table.setName("newLocations");
+        table.setUseTemporaryTable(true);
+        table.addColumn("temporarySymbolId", Sqlite::ColumnType::Integer);
+        table.addColumn("symbolId", Sqlite::ColumnType::Integer);
+        table.addColumn("line", Sqlite::ColumnType::Integer);
+        table.addColumn("column", Sqlite::ColumnType::Integer);
+        table.addColumn("sourceId", Sqlite::ColumnType::Integer);
+
+        Sqlite::SqliteImmediateTransaction<DatabaseType> transaction(database);
+        table.initialize(database);
+        transaction.commit();
+
+        return table;
+    }
+
+public:
+    Database &database;
+    Sqlite::SqliteTable symbolsTable{createSymbolsTable()};
+    Sqlite::SqliteTable locationsTable{createLocationsTable()};
+    Sqlite::SqliteTable sourcesTable{createSourcesTable()};
+    Sqlite::SqliteTable newSymbolsTablet{createNewSymbolsTable()};
+    Sqlite::SqliteTable newLocationsTable{createNewLocationsTable()};
+    WriteStatement insertSymbolsToNewSymbolsStatement{
+        "INSERT INTO newSymbols(temporarySymbolId, usr, symbolName) VALUES(?,?,?)",
+        database};
+    WriteStatement insertLocationsToNewLocationsStatement{
+        "INSERT INTO newLocations(temporarySymbolId, line, column, sourceId) VALUES(?,?,?,?)",
+        database};
+//    WriteStatement syncNewLocationsToLocationsStatement{
+//        "INSERT INTO locations(symbolId, line, column, sourceId) SELECT symbolId, line, column, sourceId FROM newLocations",
+//        database};
+    ReadStatement selectNewSourceIdsStatement{
+        "SELECT DISTINCT sourceId FROM newLocations WHERE NOT EXISTS (SELECT sourceId FROM sources WHERE newLocations.sourceId == sources.sourceId)",
+        database};
+    WriteStatement addNewSymbolsToSymbolsStatement{
+        "INSERT INTO symbols(usr, symbolname) "
+        "SELECT usr, symbolname FROM newsymbols WHERE NOT EXISTS "
+        "(SELECT usr FROM symbols WHERE usr == newsymbols.usr)",
+        database};
+    WriteStatement insertSourcesStatement{
+        "INSERT INTO sources(sourceId, sourcePath) VALUES(?,?)",
+        database};
+    WriteStatement syncNewSymbolsFromSymbolsStatement{
+        "UPDATE newSymbols SET symbolId = (SELECT symbolId FROM symbols WHERE newSymbols.usr = symbols.usr)",
+        database};
+    WriteStatement syncSymbolsIntoNewLocationsStatement{
+        "UPDATE newLocations SET symbolId = (SELECT symbolId FROM newSymbols WHERE newSymbols.temporarySymbolId = newLocations.temporarySymbolId)",
+        database};
+    WriteStatement deleteAllLocationsFromUpdatedFilesStatement{
+        "DELETE FROM locations WHERE sourceId IN (SELECT DISTINCT sourceId FROM newLocations)",
+        database};
+    WriteStatement insertNewLocationsInLocationsStatement{
+        "INSERT INTO locations(symbolId, line, column, sourceId) SELECT symbolId, line, column, sourceId FROM newLocations",
+        database};
+    WriteStatement deleteNewSymbolsTableStatement{
+        "DELETE FROM newSymbols",
+        database};
+    WriteStatement deleteNewLocationsTableStatement{
+        "DELETE FROM newLocations",
+        database};
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolentry.h b/src/tools/clangrefactoringbackend/source/symbolentry.h
index 1b97d2f22bb..432367e3c4b 100644
--- a/src/tools/clangrefactoringbackend/source/symbolentry.h
+++ b/src/tools/clangrefactoringbackend/source/symbolentry.h
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#include <stringcachefwd.h>
+
 #include <utils/smallstring.h>
 
 #include <llvm/ADT/SmallVector.h>
@@ -36,6 +38,8 @@
 
 namespace ClangBackEnd {
 
+using SymbolIndex = long long;
+
 class SymbolEntry
 {
 public:
@@ -60,7 +64,7 @@ public:
     }
 };
 
-using SymbolEntries = std::unordered_map<uint, SymbolEntry>;
+using SymbolEntries = std::unordered_map<SymbolIndex, SymbolEntry>;
 
 std::ostream &operator<<(std::ostream &out, const SymbolEntry &entry);
 
diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.cpp b/src/tools/clangrefactoringbackend/source/symbolstorage.cpp
new file mode 100644
index 00000000000..793f06f882b
--- /dev/null
+++ b/src/tools/clangrefactoringbackend/source/symbolstorage.cpp
@@ -0,0 +1,30 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "symbolstorage.h"
+
+namespace ClangBackEnd {
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h
new file mode 100644
index 00000000000..12163b0f25c
--- /dev/null
+++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "symbolstorageinterface.h"
+
+#include <sqlitetransaction.h>
+#include <stringcache.h>
+
+namespace ClangBackEnd {
+
+template <typename StatementFactory>
+class SymbolStorage : public SymbolStorageInterface
+{
+    using Transaction = Sqlite::SqliteImmediateTransaction<typename StatementFactory::DatabaseType>;
+    using ReadStatement = typename StatementFactory::ReadStatementType;
+    using WriteStatement = typename StatementFactory::WriteStatementType;
+    using Database = typename StatementFactory::DatabaseType;
+
+public:
+    SymbolStorage(StatementFactory &statementFactory,
+                  FilePathCache<> &filePathCache)
+        : m_statementFactory(statementFactory),
+          m_filePathCache(filePathCache)
+    {
+    }
+
+    void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries,
+                                      const SourceLocationEntries &sourceLocations) override
+    {
+        Transaction transaction{m_statementFactory.database};
+
+        fillTemporarySymbolsTable(symbolEntries);
+        fillTemporaryLocationsTable(sourceLocations);
+        addNewSymbolsToSymbols();
+        syncNewSymbolsFromSymbols();
+        syncSymbolsIntoNewLocations();
+        insertNewSources();
+        deleteAllLocationsFromUpdatedFiles();
+        insertNewLocationsInLocations();
+        deleteNewSymbolsTable();
+        deleteNewLocationsTable();
+
+        transaction.commit();
+    }
+
+    void fillTemporarySymbolsTable(const SymbolEntries &symbolEntries)
+    {
+        WriteStatement &statement = m_statementFactory.insertSymbolsToNewSymbolsStatement;
+
+        for (const auto &symbolEntry : symbolEntries) {
+            statement.write(symbolEntry.first,
+                            symbolEntry.second.usr,
+                            symbolEntry.second.symbolName);
+        }
+    }
+
+    void fillTemporaryLocationsTable(const SourceLocationEntries &sourceLocations)
+    {
+        WriteStatement &statement = m_statementFactory.insertLocationsToNewLocationsStatement;
+
+        for (const auto &locationsEntry : sourceLocations) {
+            statement.write(locationsEntry.symbolId,
+                            locationsEntry.line,
+                            locationsEntry.column,
+                            locationsEntry.fileId);
+        }
+    }
+
+    void addNewSymbolsToSymbols()
+    {
+        m_statementFactory.addNewSymbolsToSymbolsStatement.execute();
+    }
+
+    void syncNewSymbolsFromSymbols()
+    {
+        m_statementFactory.syncNewSymbolsFromSymbolsStatement.execute();
+    }
+
+    void syncSymbolsIntoNewLocations()
+    {
+        m_statementFactory.syncSymbolsIntoNewLocationsStatement.execute();
+    }
+
+    void deleteAllLocationsFromUpdatedFiles()
+    {
+        m_statementFactory.deleteAllLocationsFromUpdatedFilesStatement.execute();
+    }
+
+    void insertNewLocationsInLocations()
+    {
+        m_statementFactory.insertNewLocationsInLocationsStatement.execute();
+    }
+
+    FilePathIndices selectNewSourceIds() const
+    {
+         ReadStatement &statement = m_statementFactory.selectNewSourceIdsStatement;
+
+         return statement.template values<FilePathIndex>(16);
+    }
+
+    void insertNewSources()
+    {
+        WriteStatement &statement = m_statementFactory.insertSourcesStatement;
+
+        FilePathIndices newSourceIds = selectNewSourceIds();
+
+        for (FilePathIndex sourceId : newSourceIds)
+            statement.write(sourceId, m_filePathCache.string(sourceId));
+    }
+
+    void deleteNewSymbolsTable()
+    {
+        m_statementFactory.deleteNewSymbolsTableStatement.execute();
+    }
+
+    void deleteNewLocationsTable()
+    {
+        m_statementFactory.deleteNewLocationsTableStatement.execute();
+    }
+
+    SourceLocationEntries sourceLocations() const
+    {
+        return SourceLocationEntries();
+    }
+
+private:
+    StatementFactory &m_statementFactory;
+    FilePathCache<> &m_filePathCache;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h
index cea0ec8d7a4..05d449748c2 100644
--- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h
+++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h
@@ -33,7 +33,7 @@ namespace ClangBackEnd {
 class SymbolStorageInterface
 {
 public:
-    virtual void addSymbolsAndSourceLocations(const SymbolEntries &symbolEentries,
+    virtual void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries,
                                               const SourceLocationEntries &sourceLocations) = 0;
 };
 
diff --git a/tests/unit/unittest/clangpathwatcher-test.cpp b/tests/unit/unittest/clangpathwatcher-test.cpp
index ebe57c3a3d8..4bbadca3a3c 100644
--- a/tests/unit/unittest/clangpathwatcher-test.cpp
+++ b/tests/unit/unittest/clangpathwatcher-test.cpp
@@ -42,11 +42,12 @@ using testing::NiceMock;
 
 using Watcher = ClangBackEnd::ClangPathWatcher<NiceMock<MockQFileSytemWatcher>, FakeTimer>;
 using ClangBackEnd::WatcherEntry;
+using ClangBackEnd::FilePathIndices;
 
 class ClangPathWatcher : public testing::Test
 {
 protected:
-    ClangBackEnd::StringCache<Utils::PathString> pathCache;
+    ClangBackEnd::FilePathCache<> pathCache;
     NiceMock<MockClangPathWatcherNotifier> notifier;
     Watcher watcher{pathCache, &notifier};
     NiceMock<MockQFileSytemWatcher> &mockQFileSytemWatcher = watcher.fileSystemWatcher();
@@ -55,8 +56,8 @@ protected:
     Utils::SmallString id3{"id3"};
     Utils::PathString path1{"/path/path1"};
     Utils::PathString path2{"/path/path2"};
-    std::vector<uint> paths = watcher.pathCache().stringIds({path1, path2});
-    std::vector<uint> ids = watcher.idCache().stringIds({id1, id2, id3});
+    FilePathIndices paths{watcher.pathCache().stringIds({path1, path2})};
+    FilePathIndices ids{watcher.idCache().stringIds({id1, id2, id3})};
     WatcherEntry watcherEntry1{ids[0], paths[0]};
     WatcherEntry watcherEntry2{ids[1], paths[0]};
     WatcherEntry watcherEntry3{ids[0], paths[1]};
diff --git a/tests/unit/unittest/clangquery-test.cpp b/tests/unit/unittest/clangquery-test.cpp
index 3b1a196e94d..792c234570a 100644
--- a/tests/unit/unittest/clangquery-test.cpp
+++ b/tests/unit/unittest/clangquery-test.cpp
@@ -33,7 +33,7 @@
 #include <mutex>
 
 using ClangBackEnd::ClangQuery;
-using ClangBackEnd::StringCache;
+using ClangBackEnd::FilePathCache;
 
 using testing::AllOf;
 using testing::Contains;
@@ -48,7 +48,7 @@ protected:
     void SetUp() override;
 
 protected:
-    StringCache<Utils::PathString, std::mutex> filePathCache;
+    FilePathCache<std::mutex> filePathCache;
     ::ClangQuery simpleFunctionQuery{filePathCache};
     ::ClangQuery simpleClassQuery{filePathCache};
 };
diff --git a/tests/unit/unittest/clangquerygatherer-test.cpp b/tests/unit/unittest/clangquerygatherer-test.cpp
index 47719f031de..a9a191383c1 100644
--- a/tests/unit/unittest/clangquerygatherer-test.cpp
+++ b/tests/unit/unittest/clangquerygatherer-test.cpp
@@ -75,7 +75,7 @@ protected:
     void SetUp() override;
 
 protected:
-    ClangBackEnd::StringCache<Utils::PathString, std::mutex> filePathCache;
+    ClangBackEnd::FilePathCache<std::mutex> filePathCache;
     Utils::SmallString sourceContent{"#include \"query_simplefunction.h\"\nvoid f() {}"};
     FileContainer source{{TESTDATA_DIR, "query_simplefunction.cpp"},
                          sourceContent.clone(),
diff --git a/tests/unit/unittest/includecollector-test.cpp b/tests/unit/unittest/includecollector-test.cpp
index d2c0d06b710..ad405e55d7d 100644
--- a/tests/unit/unittest/includecollector-test.cpp
+++ b/tests/unit/unittest/includecollector-test.cpp
@@ -43,7 +43,7 @@ protected:
     uint id(const Utils::SmallString &path);
 
 protected:
-    ClangBackEnd::StringCache<Utils::PathString> filePathCache;
+    ClangBackEnd::FilePathCache<> filePathCache;
     ClangBackEnd::IncludeCollector collector{filePathCache};
     ClangBackEnd::IncludeCollector emptyCollector{filePathCache};
     Utils::PathStringVector excludePaths = {TESTDATA_DIR "/includecollector_main.h",
diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h
new file mode 100644
index 00000000000..55c06cb81e4
--- /dev/null
+++ b/tests/unit/unittest/mocksqlitedatabase.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "googletest.h"
+
+#include <sqlitetable.h>
+
+#include <utils/smallstringview.h>
+
+class MockSqliteDatabase
+{
+public:
+    MOCK_METHOD1(execute,
+                 void (Utils::SmallStringView sqlStatement));
+
+};
+
diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp
new file mode 100644
index 00000000000..a1813b52c70
--- /dev/null
+++ b/tests/unit/unittest/mocksqlitereadstatement.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mocksqlitereadstatement.h"
+
+template <typename ResultType,
+          typename... QueryType>
+std::vector<ResultType> values(std::size_t, QueryType...)
+{
+    FAIL() << "MockSqliteReadStatement::value was instanciated implicitly. Please add an explicit overload.";
+}
+
+template <typename... ResultType>
+std::vector<std::tuple<ResultType...>> values(std::size_t,
+                                              Utils::SmallStringView,
+                                              uint,
+                                              uint)
+{
+    FAIL() << "MockSqliteReadStatement::value was instanciated implicitly. Please add an explicit overload.";
+}
+
+template <typename... ResultType,
+          template <typename...> class ContainerType,
+          typename ElementType>
+std::vector<std::tuple<ResultType...>> tupleValues(std::size_t,
+                                                   const ContainerType<ElementType> &)
+{
+    FAIL() << "MockSqliteReadStatement::value was instanciated implicitly. Please add an explicit overload.";
+}
+
+template <>
+std::vector<FilePathIndex> MockSqliteReadStatement::values<FilePathIndex>(std::size_t reserveSize)
+{
+    return valuesReturnStdVectorInt(reserveSize);
+}
+
+template <>
+std::vector<std::tuple<int64_t, int64_t, int64_t>>
+MockSqliteReadStatement::tupleValues<int64_t, int64_t, int64_t>(
+        std::size_t reserveSize,
+        const Utils::PathString &sourcePath,
+        const uint &line,
+        const uint &column)
+{
+    return valuesReturnStdVectorTupleInt64Int64Int64(reserveSize, sourcePath, line, column);
+}
+
+template <>
+std::vector<std::tuple<int64_t, Utils::PathString>>
+MockSqliteReadStatement::tupleValues<int64_t, Utils::PathString>(std::size_t reserveSize,
+                                                                 const std::vector<int64_t> &sourceIds)
+{
+    return valuesReturnStdVectorTupleInt64PathString(reserveSize, sourceIds);
+}
diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h
new file mode 100644
index 00000000000..7e45bd39527
--- /dev/null
+++ b/tests/unit/unittest/mocksqlitereadstatement.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <stringcachefwd.h>
+
+#include "mocksqlitedatabase.h"
+
+#include <utils/smallstring.h>
+
+#include <cstdint>
+#include <tuple>
+#include <vector>
+
+using std::int64_t;
+using ClangBackEnd::FilePathIndex;
+
+class MockSqliteReadStatement
+{
+public:
+    MockSqliteReadStatement() = default;
+    MockSqliteReadStatement(Utils::SmallStringView sqlStatement, MockSqliteDatabase &)
+        : sqlStatement(sqlStatement)
+    {}
+
+    MOCK_CONST_METHOD1(valuesReturnStdVectorInt,
+                       std::vector<FilePathIndex>(std::size_t));
+
+    MOCK_CONST_METHOD4(valuesReturnStdVectorTupleInt64Int64Int64,
+                       std::vector<std::tuple<int64_t, int64_t, int64_t>>(std::size_t, Utils::SmallStringView, int64_t, int64_t));
+
+    MOCK_CONST_METHOD2(valuesReturnStdVectorTupleInt64PathString,
+                       std::vector<std::tuple<int64_t, Utils::PathString>>(std::size_t, const std::vector<int64_t> &));
+
+    template <typename ResultType,
+              typename... QueryType>
+    std::vector<ResultType> values(std::size_t, QueryType...);
+
+    template <typename... ResultType,
+              typename... QueryType>
+    std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize, const QueryType&... queryValues);
+
+    template <typename... ResultType,
+              template <typename...> class ContainerType,
+              typename ElementType>
+    std::vector<std::tuple<ResultType...>> tupleValues(std::size_t reserveSize, const ContainerType<ElementType> &queryValues);
+
+
+public:
+    Utils::SmallString sqlStatement;
+};
+
+template <>
+std::vector<int> MockSqliteReadStatement::values<int>(std::size_t reserveSize);
+
+template <>
+std::vector<std::tuple<int64_t, int64_t, int64_t>>
+MockSqliteReadStatement::tupleValues<int64_t, int64_t, int64_t>(
+        std::size_t reserveSize,
+        const Utils::PathString &sourcePath,
+        const uint &line,
+        const uint &column);
+
+template <>
+std::vector<std::tuple<int64_t, Utils::PathString>>
+MockSqliteReadStatement::tupleValues<int64_t, Utils::PathString>(std::size_t reserveSize,
+                                                                 const std::vector<int64_t> &);
+
+
diff --git a/tests/unit/unittest/mocksqlitewritestatement.h b/tests/unit/unittest/mocksqlitewritestatement.h
new file mode 100644
index 00000000000..98ea4e7e249
--- /dev/null
+++ b/tests/unit/unittest/mocksqlitewritestatement.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "mocksqlitedatabase.h"
+
+#include <utils/smallstring.h>
+
+class MockSqliteWriteStatement
+{
+public:
+    MockSqliteWriteStatement() = default;
+    MockSqliteWriteStatement(Utils::SmallStringView sqlStatement, MockSqliteDatabase &)
+        : sqlStatement(sqlStatement)
+    {}
+
+    MOCK_METHOD0(execute,
+                 void ());
+
+    MOCK_METHOD2(bind,
+                 void (int index, Utils::SmallStringView value));
+
+    MOCK_METHOD2(bindValues,
+                 void (Utils::SmallStringView, Utils::SmallStringView));
+
+    MOCK_METHOD3(write,
+                 void (uint, Utils::SmallStringView, Utils::SmallStringView));
+
+    MOCK_METHOD4(write,
+                 void (uint, uint, uint, uint));
+
+    MOCK_METHOD2(write,
+                 void (uint, Utils::SmallStringView));
+
+    Utils::SmallString sqlStatement;
+};
diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp
index 12cd50b8e5f..f03b0cd25e1 100644
--- a/tests/unit/unittest/pchcreator-test.cpp
+++ b/tests/unit/unittest/pchcreator-test.cpp
@@ -68,7 +68,7 @@ protected:
     uint id(const Utils::PathString &path);
 
 protected:
-    ClangBackEnd::StringCache<Utils::PathString> filePathCache;
+    ClangBackEnd::FilePathCache<> filePathCache;
     PathString main1Path = TESTDATA_DIR "/includecollector_main3.cpp";
     PathString main2Path = TESTDATA_DIR "/includecollector_main2.cpp";
     PathString header1Path = TESTDATA_DIR "/includecollector_header1.h";
diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp
index 8ac039b16ab..b9b170e3dc8 100644
--- a/tests/unit/unittest/pchmanagerserver-test.cpp
+++ b/tests/unit/unittest/pchmanagerserver-test.cpp
@@ -59,7 +59,7 @@ protected:
     NiceMock<MockPchCreator> mockPchCreator;
     NiceMock<MockClangPathWatcher> mockClangPathWatcher;
     NiceMock<MockProjectParts> mockProjectParts;
-    ClangBackEnd::StringCache<Utils::PathString> filePathCache;
+    ClangBackEnd::FilePathCache<> filePathCache;
     ClangBackEnd::PchManagerServer server{filePathCache, mockClangPathWatcher, mockPchCreator, mockProjectParts};
     NiceMock<MockPchManagerClient> mockPchManagerClient;
     SmallString projectPartId1 = "project1";
diff --git a/tests/unit/unittest/sourcerangeextractor-test.cpp b/tests/unit/unittest/sourcerangeextractor-test.cpp
index 42f2f0f7246..d20cd9bb93d 100644
--- a/tests/unit/unittest/sourcerangeextractor-test.cpp
+++ b/tests/unit/unittest/sourcerangeextractor-test.cpp
@@ -54,7 +54,7 @@ protected:
     TestClangTool clangTool{TESTDATA_DIR, "sourcerangeextractor_location.cpp", "",  {"cc", "sourcerangeextractor_location.cpp"}};
     ClangBackEnd::SourceRangesContainer sourceRangesContainer;
     const clang::SourceManager &sourceManager{clangTool.sourceManager()};
-    ClangBackEnd::StringCache<Utils::PathString, std::mutex> filePathCache;
+    ClangBackEnd::FilePathCache<std::mutex> filePathCache;
     ClangBackEnd::SourceRangeExtractor extractor{sourceManager, clangTool.languageOptions(), filePathCache, sourceRangesContainer};
     clang::SourceLocation startLocation = sourceManager.getLocForStartOfFile(sourceManager.getMainFileID());
     clang::SourceLocation endLocation = sourceManager.getLocForStartOfFile(sourceManager.getMainFileID()).getLocWithOffset(4);
diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp
index b3523bdc770..c052367a8bd 100644
--- a/tests/unit/unittest/sqlitestatement-test.cpp
+++ b/tests/unit/unittest/sqlitestatement-test.cpp
@@ -340,7 +340,6 @@ TEST_F(SqliteStatement, GetStructValuesWithoutArguments)
                                     Output{"poo", "40", 3}));
 }
 
-
 TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes)
 {
     SqliteReadStatement statement("SELECT name FROM test WHERE number=?", database);
diff --git a/tests/unit/unittest/storagesqlitestatementfactory-test.cpp b/tests/unit/unittest/storagesqlitestatementfactory-test.cpp
new file mode 100644
index 00000000000..98c99d908e2
--- /dev/null
+++ b/tests/unit/unittest/storagesqlitestatementfactory-test.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "googletest.h"
+
+#include "mocksqlitedatabase.h"
+#include "mocksqlitereadstatement.h"
+#include "mocksqlitewritestatement.h"
+
+#include <storagesqlitestatementfactory.h>
+
+namespace {
+
+using StatementFactory = ClangBackEnd::StorageSqliteStatementFactory<NiceMock<MockSqliteDatabase>,
+                                                                     MockSqliteReadStatement,
+                                                                     MockSqliteWriteStatement>;
+
+using Sqlite::SqliteTable;
+
+class StorageSqliteStatementFactory : public testing::Test
+{
+protected:
+    NiceMock<MockSqliteDatabase> mockDatabase;
+    StatementFactory factory{mockDatabase};
+};
+
+TEST_F(StorageSqliteStatementFactory, AddSymbolsTable)
+{
+    InSequence s;
+
+    EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
+
+    factory.createSymbolsTable();
+}
+
+TEST_F(StorageSqliteStatementFactory, AddLocationsTable)
+{
+    InSequence s;
+
+    EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
+
+    factory.createLocationsTable();
+}
+
+TEST_F(StorageSqliteStatementFactory, AddSourcesTable)
+{
+    InSequence s;
+
+    EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, sourcePath TEXT)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
+
+    factory.createSourcesTable();
+}
+
+TEST_F(StorageSqliteStatementFactory, AddNewSymbolsTable)
+{
+    InSequence s;
+
+    EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
+
+    factory.createNewSymbolsTable();
+}
+
+
+TEST_F(StorageSqliteStatementFactory, AddNewLocationsTable)
+{
+    InSequence s;
+
+    EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newLocations(temporarySymbolId INTEGER, symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
+
+    factory.createNewLocationsTable();
+}
+
+TEST_F(StorageSqliteStatementFactory, AddTablesInConstructor)
+{
+    EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))).Times(5);
+    EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))).Times(5);
+
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, sourcePath TEXT)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT)")));
+    EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newLocations(temporarySymbolId INTEGER, symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)")));
+
+    StatementFactory factory{mockDatabase};
+}
+
+TEST_F(StorageSqliteStatementFactory, InsertNewSymbolsStatement)
+{
+    ASSERT_THAT(factory.insertSymbolsToNewSymbolsStatement.sqlStatement,
+                Eq("INSERT INTO newSymbols(temporarySymbolId, usr, symbolName) VALUES(?,?,?)"));
+}
+
+TEST_F(StorageSqliteStatementFactory, InsertNewLocationsToLocations)
+{
+    ASSERT_THAT(factory.insertLocationsToNewLocationsStatement.sqlStatement,
+                Eq("INSERT INTO newLocations(temporarySymbolId, line, column, sourceId) VALUES(?,?,?,?)"));
+}
+
+TEST_F(StorageSqliteStatementFactory, SelectNewSourceIdsStatement)
+{
+    ASSERT_THAT(factory.selectNewSourceIdsStatement.sqlStatement,
+                Eq("SELECT DISTINCT sourceId FROM newLocations WHERE NOT EXISTS (SELECT sourceId FROM sources WHERE newLocations.sourceId == sources.sourceId)"));
+}
+
+TEST_F(StorageSqliteStatementFactory, AddNewSymbolsToSymbolsStatement)
+{
+    ASSERT_THAT(factory.addNewSymbolsToSymbolsStatement.sqlStatement,
+                Eq("INSERT INTO symbols(usr, symbolname) SELECT usr, symbolname FROM newsymbols WHERE NOT EXISTS (SELECT usr FROM symbols WHERE usr == newsymbols.usr)"));
+}
+
+TEST_F(StorageSqliteStatementFactory, InsertSourcesStatement)
+{
+    ASSERT_THAT(factory.insertSourcesStatement.sqlStatement,
+                Eq("INSERT INTO sources(sourceId, sourcePath) VALUES(?,?)"));
+}
+
+TEST_F(StorageSqliteStatementFactory, SyncNewSymbolsFromSymbolsStatement)
+{
+    ASSERT_THAT(factory.syncNewSymbolsFromSymbolsStatement.sqlStatement,
+                Eq("UPDATE newSymbols SET symbolId = (SELECT symbolId FROM symbols WHERE newSymbols.usr = symbols.usr)"));
+}
+
+TEST_F(StorageSqliteStatementFactory, SyncSymbolsIntoNewLocations)
+{
+    ASSERT_THAT(factory.syncSymbolsIntoNewLocationsStatement.sqlStatement,
+                Eq("UPDATE newLocations SET symbolId = (SELECT symbolId FROM newSymbols WHERE newSymbols.temporarySymbolId = newLocations.temporarySymbolId)"));
+}
+
+TEST_F(StorageSqliteStatementFactory, DeleteAllLocationsFromUpdatedFiles)
+{
+    ASSERT_THAT(factory.deleteAllLocationsFromUpdatedFilesStatement.sqlStatement,
+                Eq("DELETE FROM locations WHERE sourceId IN (SELECT DISTINCT sourceId FROM newLocations)"));
+}
+
+TEST_F(StorageSqliteStatementFactory, InsertNewLocationsInLocations)
+{
+    ASSERT_THAT(factory.insertNewLocationsInLocationsStatement.sqlStatement,
+                Eq("INSERT INTO locations(symbolId, line, column, sourceId) SELECT symbolId, line, column, sourceId FROM newLocations"));
+}
+
+TEST_F(StorageSqliteStatementFactory, DeleteNewSymbolsTableStatement)
+{
+    ASSERT_THAT(factory.deleteNewSymbolsTableStatement.sqlStatement,
+                Eq("DELETE FROM newSymbols"));
+}
+
+TEST_F(StorageSqliteStatementFactory, DeleteNewLocationsTableStatement)
+{
+    ASSERT_THAT(factory.deleteNewLocationsTableStatement.sqlStatement,
+                Eq("DELETE FROM newLocations"));
+}
+
+}
+
diff --git a/tests/unit/unittest/stringcache-test.cpp b/tests/unit/unittest/stringcache-test.cpp
index 265555f35c5..a4f989ba023 100644
--- a/tests/unit/unittest/stringcache-test.cpp
+++ b/tests/unit/unittest/stringcache-test.cpp
@@ -31,13 +31,16 @@
 
 namespace {
 
-using ClangBackEnd::StringCacheEntries;
 using ClangBackEnd::StringCacheException;
 
+using uint64 = unsigned long long;
+
+using CacheEntries = ClangBackEnd::FileCacheCacheEntries;
+
 class StringCache : public testing::Test
 {
 protected:
-    ClangBackEnd::StringCache<Utils::PathString> cache;
+    ClangBackEnd::FilePathCache<> cache;
     Utils::PathString filePath1{"/file/pathOne"};
     Utils::PathString filePath2{"/file/pathTwo"};
     Utils::PathString filePath3{"/file/pathThree"};
@@ -144,7 +147,7 @@ TEST_F(StringCache, IsNotEmpty)
 
 TEST_F(StringCache, PopulateWithEmptyVector)
 {
-    StringCacheEntries<Utils::PathString> entries;
+    CacheEntries entries;
 
     cache.uncheckedPopulate(std::move(entries));
 
@@ -153,10 +156,10 @@ TEST_F(StringCache, PopulateWithEmptyVector)
 
 TEST_F(StringCache, IsNotEmptyAfterPopulateWithSomeEntries)
 {
-    StringCacheEntries<Utils::PathString> entries{{filePath1.clone(), 0},
-                                                  {filePath2.clone(), 1},
-                                                  {filePath3.clone(), 2},
-                                                  {filePath4.clone(), 3}};
+    CacheEntries entries{{filePath1.clone(), 0},
+                         {filePath2.clone(), 1},
+                         {filePath3.clone(), 2},
+                         {filePath4.clone(), 3}};
 
     cache.uncheckedPopulate(std::move(entries));
 
@@ -165,10 +168,10 @@ TEST_F(StringCache, IsNotEmptyAfterPopulateWithSomeEntries)
 
 TEST_F(StringCache, GetEntryAfterPopulateWithSomeEntries)
 {
-    StringCacheEntries<Utils::PathString> entries{{filePath1.clone(), 0},
-                                                  {filePath2.clone(), 1},
-                                                  {filePath3.clone(), 2},
-                                                  {filePath4.clone(), 3}};
+    CacheEntries entries{{filePath1.clone(), 0},
+                         {filePath2.clone(), 1},
+                         {filePath3.clone(), 2},
+                         {filePath4.clone(), 3}};
     cache.uncheckedPopulate(std::move(entries));
 
     auto string = cache.string(2);
@@ -178,30 +181,30 @@ TEST_F(StringCache, GetEntryAfterPopulateWithSomeEntries)
 
 TEST_F(StringCache, EntriesHaveUniqueIds)
 {
-    StringCacheEntries<Utils::PathString> entries{{filePath1.clone(), 0},
-                                                  {filePath2.clone(), 1},
-                                                  {filePath3.clone(), 2},
-                                                  {filePath4.clone(), 2}};
+    CacheEntries entries{{filePath1.clone(), 0},
+                         {filePath2.clone(), 1},
+                         {filePath3.clone(), 2},
+                         {filePath4.clone(), 2}};
 
     ASSERT_THROW(cache.populate(std::move(entries)), StringCacheException);
 }
 
 TEST_F(StringCache, IdsAreHigherLowerEntriesSize)
 {
-    StringCacheEntries<Utils::PathString> entries{{filePath1.clone(), 0},
-                                                  {filePath2.clone(), 1},
-                                                  {filePath3.clone(), 4},
-                                                  {filePath4.clone(), 3}};
+    CacheEntries entries{{filePath1.clone(), 0},
+                         {filePath2.clone(), 1},
+                         {filePath3.clone(), 4},
+                         {filePath4.clone(), 3}};
 
     ASSERT_THROW(cache.populate(std::move(entries)), std::out_of_range);
 }
 
 TEST_F(StringCache, MultipleEntries)
 {
-    StringCacheEntries<Utils::PathString> entries{{filePath1.clone(), 0},
-                                                  {filePath1.clone(), 1},
-                                                  {filePath3.clone(), 2},
-                                                  {filePath4.clone(), 3}};
+    CacheEntries entries{{filePath1.clone(), 0},
+                         {filePath1.clone(), 1},
+                         {filePath3.clone(), 2},
+                         {filePath4.clone(), 3}};
 
     ASSERT_THROW(cache.populate(std::move(entries)), StringCacheException);
 }
diff --git a/tests/unit/unittest/symbolscollector-test.cpp b/tests/unit/unittest/symbolscollector-test.cpp
index 15e15ba5f14..4543c61e446 100644
--- a/tests/unit/unittest/symbolscollector-test.cpp
+++ b/tests/unit/unittest/symbolscollector-test.cpp
@@ -42,6 +42,7 @@ using testing::_;
 using ClangBackEnd::SourceLocationEntry;
 using ClangBackEnd::SymbolEntry;
 using ClangBackEnd::SymbolType;
+using ClangBackEnd::SymbolIndex;
 
 namespace {
 
@@ -53,7 +54,7 @@ protected:
         return filePathCache.stringId(string);
     }
 
-    uint symbolIdForSymbolName(const Utils::SmallString &symbolName);
+    SymbolIndex symbolIdForSymbolName(const Utils::SmallString &symbolName);
 
 protected:
     ClangBackEnd::FilePathCache<> filePathCache;
@@ -149,7 +150,7 @@ TEST_F(SymbolsCollector, ReferencedSymboldMatchesLocation)
                           Field(&SourceLocationEntry::column, 5))));
 }
 
-uint SymbolsCollector::symbolIdForSymbolName(const Utils::SmallString &symbolName)
+SymbolIndex SymbolsCollector::symbolIdForSymbolName(const Utils::SmallString &symbolName)
 {
     for (const auto &entry : collector.symbols()) {
         if (entry.second.symbolName == symbolName)
diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp
new file mode 100644
index 00000000000..ec30b9289df
--- /dev/null
+++ b/tests/unit/unittest/symbolstorage-test.cpp
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "googletest.h"
+
+#include "mocksqlitereadstatement.h"
+#include "mocksqlitewritestatement.h"
+
+#include <storagesqlitestatementfactory.h>
+#include <symbolstorage.h>
+#include <sqlitedatabase.h>
+
+#include <storagesqlitestatementfactory.h>
+
+namespace {
+
+using Utils::PathString;
+using ClangBackEnd::FilePathCache;
+using ClangBackEnd::SymbolEntries;
+using ClangBackEnd::SymbolEntry;
+using ClangBackEnd::SourceLocationEntries;
+using ClangBackEnd::SourceLocationEntry;
+using ClangBackEnd::StorageSqliteStatementFactory;
+using ClangBackEnd::SymbolType;
+using Sqlite::SqliteDatabase;
+using Sqlite::SqliteTable;
+
+using StatementFactory = StorageSqliteStatementFactory<MockSqliteDatabase,
+                                                MockSqliteReadStatement,
+                                                MockSqliteWriteStatement>;
+using Storage = ClangBackEnd::SymbolStorage<StatementFactory>;
+
+class SymbolStorage : public testing::Test
+{
+protected:
+    void SetUp();
+
+protected:
+    FilePathCache<> filePathCache;
+    NiceMock<MockSqliteDatabase> mockDatabase;
+    StatementFactory statementFactory{mockDatabase};
+
+    MockSqliteWriteStatement &insertSymbolsToNewSymbolsStatement = statementFactory.insertSymbolsToNewSymbolsStatement;
+    MockSqliteWriteStatement &insertLocationsToNewLocationsStatement = statementFactory.insertLocationsToNewLocationsStatement;
+    MockSqliteWriteStatement &insertSourcesStatement = statementFactory.insertSourcesStatement;
+    MockSqliteReadStatement &selectNewSourceIdsStatement = statementFactory.selectNewSourceIdsStatement;
+    MockSqliteWriteStatement &addNewSymbolsToSymbolsStatement = statementFactory.addNewSymbolsToSymbolsStatement;
+    MockSqliteWriteStatement &syncNewSymbolsFromSymbolsStatement = statementFactory.syncNewSymbolsFromSymbolsStatement;
+    MockSqliteWriteStatement &syncSymbolsIntoNewLocationsStatement = statementFactory.syncSymbolsIntoNewLocationsStatement;
+    MockSqliteWriteStatement &deleteAllLocationsFromUpdatedFilesStatement = statementFactory.deleteAllLocationsFromUpdatedFilesStatement;
+    MockSqliteWriteStatement &insertNewLocationsInLocationsStatement = statementFactory.insertNewLocationsInLocationsStatement;
+    MockSqliteWriteStatement &deleteNewSymbolsTableStatement = statementFactory.deleteNewSymbolsTableStatement;
+    MockSqliteWriteStatement &deleteNewLocationsTableStatement = statementFactory.deleteNewLocationsTableStatement;
+    SymbolEntries symbolEntries{{1, {"functionUSR", "function"}},
+                                {2, {"function2USR", "function2"}}};
+    SourceLocationEntries sourceLocations{{1, 3, {42, 23}, SymbolType::Declaration},
+                                          {2, 4, {7, 11}, SymbolType::Declaration}};
+    Storage storage{statementFactory, filePathCache};
+};
+
+TEST_F(SymbolStorage, CreateAndFillTemporaryLocationsTable)
+{
+    InSequence sequence;
+
+    EXPECT_CALL(insertLocationsToNewLocationsStatement, write(1, 42, 23, 3));
+    EXPECT_CALL(insertLocationsToNewLocationsStatement, write(2, 7, 11, 4));
+
+    storage.fillTemporaryLocationsTable(sourceLocations);
+}
+
+TEST_F(SymbolStorage, AddNewSymbolsToSymbols)
+{
+    EXPECT_CALL(addNewSymbolsToSymbolsStatement, execute());
+
+    storage.addNewSymbolsToSymbols();
+}
+
+TEST_F(SymbolStorage, SyncNewSymbolsFromSymbols)
+{
+    EXPECT_CALL(syncNewSymbolsFromSymbolsStatement, execute());
+
+    storage.syncNewSymbolsFromSymbols();
+}
+
+TEST_F(SymbolStorage, SyncSymbolsIntoNewLocations)
+{
+    EXPECT_CALL(syncSymbolsIntoNewLocationsStatement, execute());
+
+    storage.syncSymbolsIntoNewLocations();
+}
+
+TEST_F(SymbolStorage, DeleteAllLocationsFromUpdatedFiles)
+{
+    EXPECT_CALL(deleteAllLocationsFromUpdatedFilesStatement, execute());
+
+    storage.deleteAllLocationsFromUpdatedFiles();
+}
+
+TEST_F(SymbolStorage, InsertNewLocationsInLocations)
+{
+    EXPECT_CALL(insertNewLocationsInLocationsStatement, execute());
+
+    storage.insertNewLocationsInLocations();
+}
+
+TEST_F(SymbolStorage, SelectNewSourceIdsCalls)
+{
+    EXPECT_CALL(selectNewSourceIdsStatement, valuesReturnStdVectorInt(_));
+
+    storage.selectNewSourceIds();
+}
+
+TEST_F(SymbolStorage, SelectNewSourceIds)
+{
+    EXPECT_CALL(selectNewSourceIdsStatement, valuesReturnStdVectorInt(_));
+
+    auto sourceIds = storage.selectNewSourceIds();
+
+    ASSERT_THAT(sourceIds, ElementsAre(0, 1, 2));
+}
+
+TEST_F(SymbolStorage, InserNewSources)
+{
+    InSequence sequence;
+    EXPECT_CALL(selectNewSourceIdsStatement, valuesReturnStdVectorInt(_));
+
+    EXPECT_CALL(insertSourcesStatement, write(0, Eq("/path/to/source1")));
+    EXPECT_CALL(insertSourcesStatement, write(1, Eq("/path/to/source2")));
+    EXPECT_CALL(insertSourcesStatement, write(2, Eq("/path/to/source3")));
+
+    storage.insertNewSources();
+}
+
+
+TEST_F(SymbolStorage, DropNewSymbolsTable)
+{
+    EXPECT_CALL(deleteNewSymbolsTableStatement, execute());
+
+    storage.deleteNewSymbolsTable();
+}
+
+TEST_F(SymbolStorage, DropNewLocationsTable)
+{
+    EXPECT_CALL(deleteNewLocationsTableStatement, execute());
+
+    storage.deleteNewLocationsTable();
+}
+
+TEST_F(SymbolStorage, AddSymbolsAndSourceLocationsCallsWrite)
+{
+    InSequence sequence;
+
+    EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
+    EXPECT_CALL(insertSymbolsToNewSymbolsStatement, write(_, _, _)).Times(2);
+    EXPECT_CALL(insertLocationsToNewLocationsStatement, write(1, 42, 23, 3));
+    EXPECT_CALL(insertLocationsToNewLocationsStatement, write(2, 7, 11, 4));
+    EXPECT_CALL(addNewSymbolsToSymbolsStatement, execute());
+    EXPECT_CALL(syncNewSymbolsFromSymbolsStatement, execute());
+    EXPECT_CALL(syncSymbolsIntoNewLocationsStatement, execute());
+    EXPECT_CALL(selectNewSourceIdsStatement, valuesReturnStdVectorInt(_));
+    EXPECT_CALL(insertSourcesStatement, write(0, Eq("/path/to/source1")));
+    EXPECT_CALL(insertSourcesStatement, write(1, Eq("/path/to/source2")));
+    EXPECT_CALL(insertSourcesStatement, write(2, Eq("/path/to/source3")));
+    EXPECT_CALL(deleteAllLocationsFromUpdatedFilesStatement, execute());
+    EXPECT_CALL(insertNewLocationsInLocationsStatement, execute());
+    EXPECT_CALL(deleteNewSymbolsTableStatement, execute());
+    EXPECT_CALL(deleteNewLocationsTableStatement, execute());
+    EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
+
+    storage.addSymbolsAndSourceLocations(symbolEntries, sourceLocations);
+}
+
+void SymbolStorage::SetUp()
+{
+    ON_CALL(selectNewSourceIdsStatement, valuesReturnStdVectorInt(_))
+            .WillByDefault(Return(std::vector<FilePathIndex>{0, 1, 2}));
+
+    filePathCache.stringIds({"/path/to/source1", "/path/to/source2", "/path/to/source3"});
+}
+}
+
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 7c44c4f4ad9..667aeaa5d70 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -69,7 +69,10 @@ SOURCES += \
     symbolindexer-test.cpp \
     stringcache-test.cpp \
     unittests-main.cpp \
-    utf8-test.cpp
+    utf8-test.cpp \
+    symbolstorage-test.cpp \
+    storagesqlitestatementfactory-test.cpp \
+    mocksqlitereadstatement.cpp
 
 !isEmpty(LIBCLANG_LIBS) {
 SOURCES += \
@@ -188,7 +191,11 @@ HEADERS += \
     spydummy.h \
     testenvironment.h \
     mocksymbolscollector.h \
-    mocksymbolstorage.h
+    mocksymbolstorage.h \
+    mocksqlitewritestatement.h \
+    mocksqlitedatabase.h \
+    mocksqlitereadstatement.h \
+    google-using-directive.h
 
 !isEmpty(LIBCLANG_LIBS) {
 HEADERS += \
-- 
GitLab