diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h
index 74e031fc3fcc19785c17f4613feadf2242afc151..427d7302876e1ff89e961f08b747b641e1cc8c31 100644
--- a/src/plugins/cppeditor/cppeditorplugin.h
+++ b/src/plugins/cppeditor/cppeditorplugin.h
@@ -125,6 +125,12 @@ private slots:
     void test_FollowSymbolUnderCursor_classDestructor();
     void test_FollowSymbolUnderCursor_QObject_connect_data();
     void test_FollowSymbolUnderCursor_QObject_connect();
+    void test_FollowSymbolUnderCursor_classOperator_onOperatorToken_data();
+    void test_FollowSymbolUnderCursor_classOperator_onOperatorToken();
+    void test_FollowSymbolUnderCursor_classOperator_data();
+    void test_FollowSymbolUnderCursor_classOperator();
+    void test_FollowSymbolUnderCursor_classOperator_inOp_data();
+    void test_FollowSymbolUnderCursor_classOperator_inOp();
     void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_globalNamespace();
     void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_namespace();
     void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_insideFunction();
diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
index 4b91d3ce82140b02037a1fc813409ac5c3f436c9..bbc6129c29f13059f96108c9c77f4d580e2d0883 100644
--- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
+++ b/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp
@@ -360,6 +360,36 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &
         }
     }
 
+    // Check if we're on an operator declaration or definition.
+    if (!recognizedQtMethod) {
+        bool cursorRegionReached = false;
+        for (int i = 0; i < tokens.size(); ++i) {
+            const Token &tk = tokens.at(i);
+
+            // In this case we want to look at one token before the current position to recognize
+            // an operator if the cursor is inside the actual operator: operator[$]
+            if (unsigned(positionInBlock) >= tk.begin() && unsigned(positionInBlock) <= tk.end()) {
+                cursorRegionReached = true;
+                if (tk.is(T_OPERATOR)) {
+                    link = attemptFuncDeclDef(cursor, m_widget, theSnapshot,
+                                              documentFromSemanticInfo, symbolFinder);
+                    if (link.hasValidLinkText())
+                        return link;
+                } else if (tk.isOperator() && i > 0 && tokens.at(i - 1).is(T_OPERATOR)) {
+                    QTextCursor c = cursor;
+                    c.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor,
+                                   positionInBlock - tokens.at(i - 1).begin());
+                    link = attemptFuncDeclDef(c, m_widget, theSnapshot, documentFromSemanticInfo,
+                                              symbolFinder);
+                    if (link.hasValidLinkText())
+                        return link;
+                }
+            } else if (cursorRegionReached) {
+                break;
+            }
+        }
+    }
+
     // Now we prefer the doc from the snapshot with macros expanded.
     Document::Ptr doc = snapshot.document(m_widget->editorDocument()->filePath());
     if (!doc) {
diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
index f922b20de3c55346212dac393e8ec4d90aca6214..0ceb0446762c00d4c08553abf0093b25c2150ffc 100644
--- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
+++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp
@@ -1088,6 +1088,82 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_QObject_connect()
     test.run();
 }
 
+void CppEditorPlugin::test_FollowSymbolUnderCursor_classOperator_onOperatorToken_data()
+{
+    QTest::addColumn<bool>("toDeclaration");
+    QTest::newRow("forward") << false;
+    QTest::newRow("backward") << true;
+}
+
+void CppEditorPlugin::test_FollowSymbolUnderCursor_classOperator_onOperatorToken()
+{
+    QFETCH(bool, toDeclaration);
+
+    QByteArray source =
+            "class Foo {\n"
+            "    void @operator[](size_t idx);\n"
+            "};\n\n"
+            "void Foo::$operator[](size_t idx)\n"
+            "{\n"
+            "}\n";
+    if (toDeclaration)
+        source.replace('@', '#').replace('$', '@').replace('#', '$');
+    TestCase test(TestCase::FollowSymbolUnderCursorAction, source);
+    test.run();
+}
+
+void CppEditorPlugin::test_FollowSymbolUnderCursor_classOperator_data()
+{
+    test_FollowSymbolUnderCursor_classOperator_onOperatorToken_data();
+}
+
+void CppEditorPlugin::test_FollowSymbolUnderCursor_classOperator()
+{
+    QFETCH(bool, toDeclaration);
+
+    QByteArray source =
+            "class Foo {\n"
+            "    void $2operator@1[](size_t idx);\n"
+            "};\n\n"
+            "void Foo::$1operator@2[](size_t idx)\n"
+            "{\n"
+            "}\n";
+    if (toDeclaration)
+        source.replace("@1", QByteArray()).replace("$1", QByteArray())
+                .replace("@2", "@").replace("$2", "$");
+    else
+        source.replace("@2", QByteArray()).replace("$2", QByteArray())
+                .replace("@1", "@").replace("$1", "$");
+    TestCase test(TestCase::FollowSymbolUnderCursorAction, source);
+    test.run();
+}
+
+void CppEditorPlugin::test_FollowSymbolUnderCursor_classOperator_inOp_data()
+{
+    test_FollowSymbolUnderCursor_classOperator_onOperatorToken_data();
+}
+
+void CppEditorPlugin::test_FollowSymbolUnderCursor_classOperator_inOp()
+{
+    QFETCH(bool, toDeclaration);
+
+    QByteArray source =
+            "class Foo {\n"
+            "    void $2operator[@1](size_t idx);\n"
+            "};\n\n"
+            "void Foo::$1operator[@2](size_t idx)\n"
+            "{\n"
+            "}\n";
+    if (toDeclaration)
+        source.replace("@1", QByteArray()).replace("$1", QByteArray())
+                .replace("@2", "@").replace("$2", "$");
+    else
+        source.replace("@2", QByteArray()).replace("$2", QByteArray())
+                .replace("@1", "@").replace("$1", "$");
+    TestCase test(TestCase::FollowSymbolUnderCursorAction, source);
+    test.run();
+}
+
 void CppEditorPlugin::test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_globalNamespace()
 {
     const QByteArray source =
diff --git a/src/plugins/cpptools/symbolfinder.cpp b/src/plugins/cpptools/symbolfinder.cpp
index d3565d7b154452487c87ef5905ec8b872cb8f37f..5994ededbf3117d1f5ba87e14fe872988ce8117a 100644
--- a/src/plugins/cpptools/symbolfinder.cpp
+++ b/src/plugins/cpptools/symbolfinder.cpp
@@ -244,6 +244,24 @@ Class *SymbolFinder::findMatchingClassDeclaration(Symbol *declaration, const Sna
     return 0;
 }
 
+static void findDeclarationOfSymbol(Symbol *s,
+                                    Function *functionType,
+                                    QList<Declaration *> *typeMatch,
+                                    QList<Declaration *> *argumentCountMatch,
+                                    QList<Declaration *> *nameMatch)
+{
+    if (Declaration *decl = s->asDeclaration()) {
+        if (Function *declFunTy = decl->type()->asFunctionType()) {
+            if (functionType->isEqualTo(declFunTy))
+                typeMatch->prepend(decl);
+            else if (functionType->argumentCount() == declFunTy->argumentCount())
+                argumentCountMatch->prepend(decl);
+            else
+                nameMatch->append(decl);
+        }
+    }
+}
+
 void SymbolFinder::findMatchingDeclaration(const LookupContext &context,
                                            Function *functionType,
                                            QList<Declaration *> *typeMatch,
@@ -280,26 +298,33 @@ void SymbolFinder::findMatchingDeclaration(const LookupContext &context,
     }
 
     const Identifier *funcId = functionName->identifier();
-    if (!funcId) // E.g. operator, which we might be able to handle in the future...
-        return;
+    OperatorNameId::Kind operatorNameId = OperatorNameId::InvalidOp;
+
+    if (!funcId) {
+        if (!qName)
+            return;
+        const OperatorNameId * const onid = qName->name()->asOperatorNameId();
+        if (!onid)
+            return;
+        operatorNameId = onid->kind();
+    }
 
     foreach (Symbol *s, binding->symbols()) {
         Scope *scope = s->asScope();
         if (!scope)
             continue;
 
-        for (Symbol *s = scope->find(funcId); s; s = s->next()) {
-            if (!s->name() || !funcId->isEqualTo(s->identifier()) || !s->type()->isFunctionType())
-                continue;
-            if (Declaration *decl = s->asDeclaration()) {
-                if (Function *declFunTy = decl->type()->asFunctionType()) {
-                    if (functionType->isEqualTo(declFunTy))
-                        typeMatch->prepend(decl);
-                    else if (functionType->argumentCount() == declFunTy->argumentCount())
-                        argumentCountMatch->prepend(decl);
-                    else
-                        nameMatch->append(decl);
-                }
+        if (funcId) {
+            for (Symbol *s = scope->find(funcId); s; s = s->next()) {
+                if (!s->name() || !funcId->isEqualTo(s->identifier()) || !s->type()->isFunctionType())
+                    continue;
+                findDeclarationOfSymbol(s, functionType, typeMatch, argumentCountMatch, nameMatch);
+            }
+        } else {
+            for (Symbol *s = scope->find(operatorNameId); s; s = s->next()) {
+                if (!s->name() || !s->type()->isFunctionType())
+                    continue;
+                findDeclarationOfSymbol(s, functionType, typeMatch, argumentCountMatch, nameMatch);
             }
         }
     }