diff --git a/src/plugins/cpptools/builtinindexingsupport.cpp b/src/plugins/cpptools/builtinindexingsupport.cpp
index 60a33ad7ad0a981959d8c351a87aed687af6fed7..fc51ad12f90a9c7a97e17e80dd181e318c7464ff 100644
--- a/src/plugins/cpptools/builtinindexingsupport.cpp
+++ b/src/plugins/cpptools/builtinindexingsupport.cpp
@@ -125,7 +125,7 @@ public:
                 break;
             if (m_fileNames.isEmpty() || m_fileNames.contains(it.value()->fileName())) {
                 QVector<Core::SearchResultItem> resultItems;
-                search(it.value())->visitAllChildren([&](const IndexItem::Ptr &info) {
+                auto filter = [&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
                     if (matcher.indexIn(info->symbolName()) != -1) {
                         QString text = info->symbolName();
                         QString scope = info->symbolScope();
@@ -148,7 +148,10 @@ public:
                         item.userData = qVariantFromValue(info);
                         resultItems << item;
                     }
-                });
+
+                    return IndexItem::Recurse;
+                };
+                search(it.value())->visitAllChildren(filter);
                 if (!resultItems.isEmpty())
                     future.reportResults(resultItems);
             }
diff --git a/src/plugins/cpptools/cppclassesfilter.cpp b/src/plugins/cpptools/cppclassesfilter.cpp
index 5835b4346b56851c89812993498b6ecc6bf438e8..46519f63da53b0a2f3bb0835b928a63ae05afd34 100644
--- a/src/plugins/cpptools/cppclassesfilter.cpp
+++ b/src/plugins/cpptools/cppclassesfilter.cpp
@@ -45,11 +45,6 @@ CppClassesFilter::~CppClassesFilter()
 {
 }
 
-QList<QList<IndexItem::Ptr> > CppClassesFilter::itemsToMatchUserInputAgainst() const
-{
-    return QList<QList<CppTools::IndexItem::Ptr> >() << m_data->classes();
-}
-
 Core::LocatorFilterEntry CppClassesFilter::filterEntryFromIndexItem(IndexItem::Ptr info)
 {
     const QVariant id = qVariantFromValue(info);
diff --git a/src/plugins/cpptools/cppclassesfilter.h b/src/plugins/cpptools/cppclassesfilter.h
index 446a90b7cae47a64f79b01f223148f8d703c927b..7fd99416a09abf1d7530237f3ce1bc428ef9636f 100644
--- a/src/plugins/cpptools/cppclassesfilter.h
+++ b/src/plugins/cpptools/cppclassesfilter.h
@@ -34,19 +34,22 @@
 #include "cpplocatordata.h"
 #include "cpplocatorfilter.h"
 
+#include <utils/qtcoverride.h>
+
 namespace CppTools {
 
+// TODO: un-export this
 class CPPTOOLS_EXPORT CppClassesFilter : public Internal::CppLocatorFilter
 {
     Q_OBJECT
 
 public:
-    CppClassesFilter(Internal::CppLocatorData *locatorData);
-    ~CppClassesFilter();
+    CppClassesFilter(CppLocatorData *locatorData);
+    ~CppClassesFilter() QTC_OVERRIDE;
 
-private:
-    QList<QList<CppTools::IndexItem::Ptr> > itemsToMatchUserInputAgainst() const;
-    Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info);
+protected:
+    IndexItem::ItemType matchTypes() const QTC_OVERRIDE { return IndexItem::Class; }
+    Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info) QTC_OVERRIDE;
 };
 
 } // namespace CppTools
diff --git a/src/plugins/cpptools/cppcurrentdocumentfilter.cpp b/src/plugins/cpptools/cppcurrentdocumentfilter.cpp
index ef3242c15d86623e216c4cb349b631e87de8fada..cd20cfdc5476dd29812711d4e0fa4c56bb83394b 100644
--- a/src/plugins/cpptools/cppcurrentdocumentfilter.cpp
+++ b/src/plugins/cpptools/cppcurrentdocumentfilter.cpp
@@ -78,10 +78,13 @@ QList<Core::LocatorFilterEntry> CppCurrentDocumentFilter::matchesFor(
     if (m_itemsOfCurrentDoc.isEmpty()) {
         Snapshot snapshot = m_modelManager->snapshot();
         Document::Ptr thisDocument = snapshot.document(m_currentFileName);
-        if (thisDocument)
-            search(thisDocument)->visitAllChildren([&](const IndexItem::Ptr &info){
+        if (thisDocument) {
+            IndexItem::Ptr rootNode = search(thisDocument);
+            rootNode->visitAllChildren([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
                 m_itemsOfCurrentDoc.append(info);
+                return IndexItem::Recurse;
             });
+        }
     }
 
     const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry);
diff --git a/src/plugins/cpptools/cppfunctionsfilter.cpp b/src/plugins/cpptools/cppfunctionsfilter.cpp
index ecdb8a971cfd1bfff17861a7abe133b7efdae2e8..883766bc41f6c3375198124252eb2ed9cb89ead4 100644
--- a/src/plugins/cpptools/cppfunctionsfilter.cpp
+++ b/src/plugins/cpptools/cppfunctionsfilter.cpp
@@ -45,11 +45,6 @@ CppFunctionsFilter::~CppFunctionsFilter()
 {
 }
 
-QList<QList<CppTools::IndexItem::Ptr> > CppFunctionsFilter::itemsToMatchUserInputAgainst() const
-{
-    return QList<QList<CppTools::IndexItem::Ptr> >() << m_data->functions();
-}
-
 Core::LocatorFilterEntry CppFunctionsFilter::filterEntryFromIndexItem(IndexItem::Ptr info)
 {
     const QVariant id = qVariantFromValue(info);
diff --git a/src/plugins/cpptools/cppfunctionsfilter.h b/src/plugins/cpptools/cppfunctionsfilter.h
index ba0f9d49dbdcc2c370c6a792752d146249c462a9..d024afc4e15ef7691e98357de04575ff9311b869 100644
--- a/src/plugins/cpptools/cppfunctionsfilter.h
+++ b/src/plugins/cpptools/cppfunctionsfilter.h
@@ -33,6 +33,8 @@
 #include "cpplocatordata.h"
 #include "cpplocatorfilter.h"
 
+#include <utils/qtcoverride.h>
+
 namespace CppTools {
 namespace Internal {
 
@@ -42,11 +44,11 @@ class CppFunctionsFilter : public CppLocatorFilter
 
 public:
     CppFunctionsFilter(CppLocatorData *locatorData);
-    ~CppFunctionsFilter();
+    ~CppFunctionsFilter() QTC_OVERRIDE;
 
-private:
-    QList<QList<IndexItem::Ptr> > itemsToMatchUserInputAgainst() const;
-    Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info);
+protected:
+    IndexItem::ItemType matchTypes() const QTC_OVERRIDE { return IndexItem::Function; }
+    Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info) QTC_OVERRIDE;
 };
 
 } // namespace Internal
diff --git a/src/plugins/cpptools/cpplocatordata.cpp b/src/plugins/cpptools/cpplocatordata.cpp
index 986834274dbfb512604b0e6bb50a48843edc949b..26665916b36aa24f92c3fd97f352ba52d8c6b551 100644
--- a/src/plugins/cpptools/cpplocatordata.cpp
+++ b/src/plugins/cpptools/cpplocatordata.cpp
@@ -33,42 +33,17 @@
 using namespace CppTools;
 using namespace CppTools::Internal;
 
-static const int MaxPendingDocuments = 10;
+enum { MaxPendingDocuments = 10 };
 
-CppLocatorData::CppLocatorData(CppModelManager *modelManager)
-    : m_modelManager(modelManager)
-    , m_strings(CppToolsPlugin::stringTable())
-    , m_search(m_strings)
+CppLocatorData::CppLocatorData()
+    : m_strings(&CppToolsPlugin::stringTable())
+    , m_search(CppToolsPlugin::stringTable())
     , m_pendingDocumentsMutex(QMutex::Recursive)
 {
-    m_search.setSymbolsToSearchFor(SymbolSearcher::Enums
-                                 | SymbolSearcher::Classes
-                                 | SymbolSearcher::Functions);
+    m_search.setSymbolsToSearchFor(SymbolSearcher::Enums |
+                                   SymbolSearcher::Classes |
+                                   SymbolSearcher::Functions);
     m_pendingDocuments.reserve(MaxPendingDocuments);
-
-    connect(m_modelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
-            this, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
-
-    connect(m_modelManager, SIGNAL(aboutToRemoveFiles(QStringList)),
-            this, SLOT(onAboutToRemoveFiles(QStringList)));
-}
-
-QList<IndexItem::Ptr> CppLocatorData::enums()
-{
-    flushPendingDocument(true);
-    return allIndexItems(m_allEnums);
-}
-
-QList<IndexItem::Ptr> CppLocatorData::classes()
-{
-    flushPendingDocument(true);
-    return allIndexItems(m_allClasses);
-}
-
-QList<IndexItem::Ptr> CppLocatorData::functions()
-{
-    flushPendingDocument(true);
-    return allIndexItems(m_allFunctions);
 }
 
 void CppLocatorData::onDocumentUpdated(const CPlusPlus::Document::Ptr &document)
@@ -93,57 +68,37 @@ void CppLocatorData::onDocumentUpdated(const CPlusPlus::Document::Ptr &document)
 
 void CppLocatorData::onAboutToRemoveFiles(const QStringList &files)
 {
-    QMutexLocker locker(&m_pendingDocumentsMutex);
+    if (files.isEmpty())
+        return;
 
-    for (int i = 0; i < m_pendingDocuments.size(); ) {
-        if (files.contains(m_pendingDocuments.at(i)->fileName()))
-            m_pendingDocuments.remove(i);
-        else
-            ++i;
-    }
+    QMutexLocker locker(&m_pendingDocumentsMutex);
 
     foreach (const QString &file, files) {
-        m_allEnums.remove(file);
-        m_allClasses.remove(file);
-        m_allFunctions.remove(file);
+        m_infosByFile.remove(file);
+
+        for (int i = 0; i < m_pendingDocuments.size(); ++i) {
+            if (m_pendingDocuments.at(i)->fileName() == file) {
+                m_pendingDocuments.remove(i);
+                break;
+            }
+        }
     }
 
-    m_strings.scheduleGC();
+    m_strings->scheduleGC();
+    flushPendingDocument(false);
 }
 
-void CppLocatorData::flushPendingDocument(bool force)
+void CppLocatorData::flushPendingDocument(bool force) const
 {
+    // TODO: move this off the UI thread and into a future.
     QMutexLocker locker(&m_pendingDocumentsMutex);
     if (!force && m_pendingDocuments.size() < MaxPendingDocuments)
         return;
+    if (m_pendingDocuments.isEmpty())
+        return;
 
-    foreach (CPlusPlus::Document::Ptr doc, m_pendingDocuments) {
-        const QString fileName = findOrInsertFilePath(doc->fileName());
-
-        QList<IndexItem::Ptr> resultsEnums;
-        QList<IndexItem::Ptr> resultsClasses;
-        QList<IndexItem::Ptr> resultsFunctions;
-
-        m_search(doc)->visitAllChildren([&](const IndexItem::Ptr &info) {
-            switch (info->type()) {
-            case IndexItem::Enum:
-                resultsEnums.append(info);
-                break;
-            case IndexItem::Class:
-                resultsClasses.append(info);
-                break;
-            case IndexItem::Function:
-                resultsFunctions.append(info);
-                break;
-            default:
-                break;
-            }
-        });
-
-        m_allEnums[fileName] = resultsEnums;
-        m_allClasses[fileName] = resultsClasses;
-        m_allFunctions[fileName] = resultsFunctions;
-    }
+    foreach (CPlusPlus::Document::Ptr doc, m_pendingDocuments)
+        m_infosByFile.insert(findOrInsertFilePath(doc->fileName()), m_search(doc));
 
     m_pendingDocuments.clear();
     m_pendingDocuments.reserve(MaxPendingDocuments);
diff --git a/src/plugins/cpptools/cpplocatordata.h b/src/plugins/cpptools/cpplocatordata.h
index 0feda706c4f8fe75b069a99c77b31a7158cdd0e8..97fce390ce07dd184464d76a879e61eb1c3af4f2 100644
--- a/src/plugins/cpptools/cpplocatordata.h
+++ b/src/plugins/cpptools/cpplocatordata.h
@@ -27,58 +27,66 @@
 **
 ****************************************************************************/
 
-
 #ifndef CPPLOCATORDATA_H
 #define CPPLOCATORDATA_H
 
+#include <functional>
 #include <QHash>
-#include <QVector>
 
 #include <cplusplus/CppDocument.h>
 
+#include "cpptools_global.h"
 #include "cppmodelmanager.h"
 #include "searchsymbols.h"
 #include "stringtable.h"
 
 namespace CppTools {
+
 namespace Internal {
+class CppToolsPlugin;
+} // Internal namespace
 
 class CppLocatorData : public QObject
 {
     Q_OBJECT
-public:
-    explicit CppLocatorData(CppModelManager *modelManager);
 
-    QList<IndexItem::Ptr> enums();
-    QList<IndexItem::Ptr> classes();
-    QList<IndexItem::Ptr> functions();
+    // Only one instance, created by the CppToolsPlugin.
+    CppLocatorData();
+    friend class Internal::CppToolsPlugin;
 
-private slots:
+public:
+    void filterAllFiles(IndexItem::Visitor func) const
+    {
+        flushPendingDocument(true);
+        QMutexLocker locker(&m_pendingDocumentsMutex);
+        QHash<QString, IndexItem::Ptr> infosByFile = m_infosByFile;
+        locker.unlock();
+        for (auto i = infosByFile.constBegin(), ei = infosByFile.constEnd(); i != ei; ++i)
+            if (i.value()->visitAllChildren(func) == IndexItem::Break)
+                return;
+    }
+
+public slots:
     void onDocumentUpdated(const CPlusPlus::Document::Ptr &document);
     void onAboutToRemoveFiles(const QStringList &files);
 
 private:
-    void flushPendingDocument(bool force);
+    void flushPendingDocument(bool force) const;
     QList<IndexItem::Ptr> allIndexItems(const QHash<QString, QList<IndexItem::Ptr>> &items) const;
 
-    QString findOrInsertFilePath(const QString &path)
-    { return m_strings.insert(path); }
+    QString findOrInsertFilePath(const QString &path) const
+    { return m_strings->insert(path); }
 
 private:
-    CppModelManager *m_modelManager;
-
-    StringTable &m_strings; // Used to avoid QString duplication
+    Internal::StringTable *m_strings; // Used to avoid QString duplication
 
-    SearchSymbols m_search;
-    QHash<QString, QList<IndexItem::Ptr> > m_allEnums;
-    QHash<QString, QList<IndexItem::Ptr> > m_allClasses;
-    QHash<QString, QList<IndexItem::Ptr> > m_allFunctions;
+    mutable SearchSymbols m_search;
+    mutable QHash<QString, IndexItem::Ptr> m_infosByFile;
 
     mutable QMutex m_pendingDocumentsMutex;
-    QVector<CPlusPlus::Document::Ptr> m_pendingDocuments;
+    mutable QVector<CPlusPlus::Document::Ptr> m_pendingDocuments;
 };
 
-} // namespace Internal
-} // namespace CppTools
+} // CppTools namespace
 
 #endif // CPPLOCATORDATA_H
diff --git a/src/plugins/cpptools/cpplocatorfilter.cpp b/src/plugins/cpptools/cpplocatorfilter.cpp
index 3c967c4d32fd3e447f27e5ca1b27eda00e635c2e..1d36047a8465456bd2fbe94e4a31c7f70dfb0b40 100644
--- a/src/plugins/cpptools/cpplocatorfilter.cpp
+++ b/src/plugins/cpptools/cpplocatorfilter.cpp
@@ -65,14 +65,6 @@ void CppLocatorFilter::refresh(QFutureInterface<void> &future)
     Q_UNUSED(future)
 }
 
-QList<QList<CppTools::IndexItem::Ptr> > CppLocatorFilter::itemsToMatchUserInputAgainst() const
-{
-    return QList<QList<CppTools::IndexItem::Ptr> >()
-        << m_data->classes()
-        << m_data->functions()
-        << m_data->enums();
-}
-
 static bool compareLexigraphically(const Core::LocatorFilterEntry &a,
                                    const Core::LocatorFilterEntry &b)
 {
@@ -93,16 +85,15 @@ QList<Core::LocatorFilterEntry> CppLocatorFilter::matchesFor(
     bool hasWildcard = (entry.contains(asterisk) || entry.contains(QLatin1Char('?')));
     bool hasColonColon = entry.contains(QLatin1String("::"));
     const Qt::CaseSensitivity caseSensitivityForPrefix = caseSensitivity(entry);
+    const IndexItem::ItemType wanted = matchTypes();
 
-    const QList<QList<CppTools::IndexItem::Ptr> > itemLists = itemsToMatchUserInputAgainst();
-    foreach (const QList<CppTools::IndexItem::Ptr> &items, itemLists) {
-        foreach (IndexItem::Ptr info, items) {
-            if (future.isCanceled())
-                break;
-            const QString matchString = hasColonColon ? info->scopedSymbolName()
-                                                      : info->symbolName();
-            if ((hasWildcard && regexp.exactMatch(matchString))
-                || (!hasWildcard && matcher.indexIn(matchString) != -1)) {
+    m_data->filterAllFiles([&](const IndexItem::Ptr &info) -> IndexItem::VisitorResult {
+        if (future.isCanceled())
+            return IndexItem::Break;
+        if (info->type() & wanted) {
+            const QString matchString = hasColonColon ? info->scopedSymbolName() : info->symbolName();
+            if ((hasWildcard && regexp.exactMatch(matchString)) ||
+                    (!hasWildcard && matcher.indexIn(matchString) != -1)) {
                 const Core::LocatorFilterEntry filterEntry = filterEntryFromIndexItem(info);
                 if (matchString.startsWith(entry, caseSensitivityForPrefix))
                     betterEntries.append(filterEntry);
@@ -110,7 +101,12 @@ QList<Core::LocatorFilterEntry> CppLocatorFilter::matchesFor(
                     goodEntries.append(filterEntry);
             }
         }
-    }
+
+        if (info->type() & IndexItem::Enum)
+            return IndexItem::Continue;
+        else
+            return IndexItem::Recurse;
+    });
 
     if (goodEntries.size() < 1000)
         qStableSort(goodEntries.begin(), goodEntries.end(), compareLexigraphically);
diff --git a/src/plugins/cpptools/cpplocatorfilter.h b/src/plugins/cpptools/cpplocatorfilter.h
index 07d5ce5fb2378abb5da4d94813505758d965ce98..dbf7eed6f041f5380a0b6d2c261ff10c7d1b3ba4 100644
--- a/src/plugins/cpptools/cpplocatorfilter.h
+++ b/src/plugins/cpptools/cpplocatorfilter.h
@@ -54,7 +54,7 @@ public:
     void refresh(QFutureInterface<void> &future);
 
 protected:
-    virtual QList<QList<IndexItem::Ptr> > itemsToMatchUserInputAgainst() const;
+    virtual IndexItem::ItemType matchTypes() const { return IndexItem::All; }
     virtual Core::LocatorFilterEntry filterEntryFromIndexItem(IndexItem::Ptr info);
 
 protected:
diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp
index 7e9f1d061d929666cc98d6bc503240b193cdc7d0..44179a1fb4ce618e04e214d53990ea03142657d3 100644
--- a/src/plugins/cpptools/cpptoolsplugin.cpp
+++ b/src/plugins/cpptools/cpptoolsplugin.cpp
@@ -131,7 +131,13 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
     connect(DocumentManager::instance(), SIGNAL(filesChangedInternally(QStringList)),
             modelManager, SLOT(updateSourceFiles(QStringList)));
 
-    CppLocatorData *locatorData = new CppLocatorData(modelManager);
+    CppLocatorData *locatorData = new CppLocatorData;
+    connect(modelManager, SIGNAL(documentUpdated(CPlusPlus::Document::Ptr)),
+            locatorData, SLOT(onDocumentUpdated(CPlusPlus::Document::Ptr)));
+
+    connect(modelManager, SIGNAL(aboutToRemoveFiles(QStringList)),
+            locatorData, SLOT(onAboutToRemoveFiles(QStringList)));
+
     addAutoReleasedObject(locatorData);
     addAutoReleasedObject(new CppLocatorFilter(locatorData));
     addAutoReleasedObject(new CppClassesFilter(locatorData));
diff --git a/src/plugins/cpptools/indexitem.cpp b/src/plugins/cpptools/indexitem.cpp
index 66784975d0f342f45bd05236ea3de5b10a387619..4790378479c1ba64cb115c5703a6d2455360eff3 100644
--- a/src/plugins/cpptools/indexitem.cpp
+++ b/src/plugins/cpptools/indexitem.cpp
@@ -44,12 +44,3 @@ void IndexItem::squeeze()
     for (int i = 0, ei = m_children.size(); i != ei; ++i)
         m_children[i]->squeeze();
 }
-
-void IndexItem::visitAllChildren(std::function<void (const IndexItem::Ptr &)> f) const
-{
-    foreach (const IndexItem::Ptr &child, m_children) {
-        f(child);
-        if (!child->m_children.isEmpty())
-            child->visitAllChildren(f);
-    }
-}
diff --git a/src/plugins/cpptools/indexitem.h b/src/plugins/cpptools/indexitem.h
index 2ebf070f4baead724e25b92cdeda7dd3d9691f9a..40b9782e8c0c3a172d5044fc00b563a50c0269a6 100644
--- a/src/plugins/cpptools/indexitem.h
+++ b/src/plugins/cpptools/indexitem.h
@@ -38,6 +38,8 @@
 #include <QSharedPointer>
 #include <QMetaType>
 
+#include <functional>
+
 namespace CppTools {
 
 class CPPTOOLS_EXPORT IndexItem
@@ -45,7 +47,14 @@ class CPPTOOLS_EXPORT IndexItem
     Q_DISABLE_COPY(IndexItem)
 
 public:
-    enum ItemType { Enum, Class, Function, Declaration };
+    enum ItemType {
+        Enum        = 1 << 0,
+        Class       = 1 << 1,
+        Function    = 1 << 2,
+        Declaration = 1 << 3,
+
+        All = Enum | Class | Function | Declaration
+    };
 
 private:
     IndexItem(const QString &symbolName,
@@ -139,7 +148,34 @@ public:
     void addChild(IndexItem::Ptr childItem) { m_children.append(childItem); }
     void squeeze();
 
-    void visitAllChildren(std::function<void (const IndexItem::Ptr &)> f) const;
+    enum VisitorResult {
+        Break, /// terminates traversal
+        Continue, /// continues traversal with the next sibling
+        Recurse, /// continues traversal with the children
+    };
+
+    typedef std::function<VisitorResult (const IndexItem::Ptr &)> Visitor;
+
+    VisitorResult visitAllChildren(Visitor callback) const
+    {
+        VisitorResult result = Recurse;
+        foreach (const IndexItem::Ptr &child, m_children) {
+            result = callback(child);
+            switch (result) {
+            case Break:
+                return Break;
+            case Continue:
+                continue;
+            case Recurse:
+                if (!child->m_children.isEmpty()) {
+                    result = child->visitAllChildren(callback);
+                    if (result == Break)
+                        return Break;
+                }
+            }
+        }
+        return result;
+    }
 
 private:
     QString m_symbolName; // as found in the code, therefore might be qualified