diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp
index 27126be286da0be9ce75d66f5bc1183118435675..b7b95d8b930c7d7cce42d6635d0f319b770d73b2 100644
--- a/src/plugins/cppeditor/cppchecksymbols.cpp
+++ b/src/plugins/cppeditor/cppchecksymbols.cpp
@@ -63,6 +63,7 @@ class CollectTypes: protected SymbolVisitor
     Snapshot _snapshot;
     QSet<QByteArray> _types;
     QSet<QByteArray> _members;
+    QSet<QByteArray> _virtualMethods;
     QList<ScopedSymbol *> _scopes;
     QList<NameAST *> _names;
     bool _mainDocument;
@@ -85,6 +86,11 @@ public:
         return _members;
     }
 
+    const QSet<QByteArray> &virtualMethods() const
+    {
+        return _virtualMethods;
+    }
+
     const QList<ScopedSymbol *> &scopes() const
     {
         return _scopes;
@@ -153,6 +159,18 @@ protected:
         }
     }
 
+    void addVirtualMethod(const Name *name)
+    {
+        if (! name) {
+            return;
+
+        } else if (name->isNameId()) {
+            const Identifier *id = name->identifier();
+            _virtualMethods.insert(QByteArray::fromRawData(id->chars(), id->size()));
+
+        }
+    }
+
     void addScope(ScopedSymbol *symbol)
     {
         if (_mainDocument)
@@ -167,6 +185,9 @@ protected:
 
     virtual bool visit(Function *symbol)
     {
+        if (symbol->isVirtual())
+            addVirtualMethod(symbol->name());
+
         for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
             Scope *scope = p->scope();
             for (unsigned i = 0; i < scope->symbolCount(); ++i)
@@ -191,6 +212,11 @@ protected:
 
     virtual bool visit(Declaration *symbol)
     {
+        if (Function *funTy = symbol->type()->asFunctionType()) {
+            if (funTy->isVirtual())
+                addVirtualMethod(symbol->name());
+        }
+
         if (symbol->isTypedef())
             addType(symbol->name());
         else if (! symbol->type()->isFunctionType() && symbol->enclosingSymbol()->isClass())
@@ -298,6 +324,7 @@ CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context)
     CollectTypes collectTypes(doc, context.snapshot());
     _potentialTypes = collectTypes.types();
     _potentialMembers = collectTypes.members();
+    _potentialVirtualMethods = collectTypes.virtualMethods();
     _scopes = collectTypes.scopes();
     _flushRequested = false;
     _flushLine = 0;
@@ -370,8 +397,23 @@ bool CheckSymbols::visit(UsingDirectiveAST *)
     return true;
 }
 
-bool CheckSymbols::visit(SimpleDeclarationAST *)
-{
+bool CheckSymbols::visit(SimpleDeclarationAST *ast)
+{
+    if (ast->declarator_list && !ast->declarator_list->next) {
+        if (ast->symbols && ! ast->symbols->next && !ast->symbols->value->isGenerated()) {
+            Symbol *decl = ast->symbols->value;
+            if (NameAST *declId = declaratorId(ast->declarator_list->value)) {
+                if (Function *funTy = decl->type()->asFunctionType()) {
+                    if (funTy->isVirtual()) {
+                        addVirtualMethodUsage(declId);
+                    } else if (maybeVirtualMethod(decl->name())) {
+                        addVirtualMethodUsage(_context.lookup(decl->name(), decl->scope()), declId, funTy->argumentCount());
+                    }
+                }
+            }
+        }
+    }
+
     return true;
 }
 
@@ -405,6 +447,52 @@ bool CheckSymbols::visit(MemberAccessAST *ast)
     return false;
 }
 
+bool CheckSymbols::visit(CallAST *ast)
+{
+    if (ast->base_expression) {
+        accept(ast->base_expression);
+
+        unsigned argumentCount = 0;
+
+        for (ExpressionListAST *it = ast->expression_list; it; it = it->next)
+            ++argumentCount;
+
+        if (MemberAccessAST *access = ast->base_expression->asMemberAccess()) {
+            if (access->member_name && access->member_name->name) {
+                if (maybeVirtualMethod(access->member_name->name)) {
+                    Scope *scope = findScope(access);
+                    const QByteArray expression = textOf(access);
+
+                    const QList<LookupItem> candidates = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
+                    addVirtualMethodUsage(candidates, access->member_name, argumentCount);
+                }
+            }
+        } else if (IdExpressionAST *idExpr = ast->base_expression->asIdExpression()) {
+            if (const Name *name = idExpr->name->name) {
+                if (maybeVirtualMethod(name)) {
+                    Scope *scope = findScope(idExpr);
+                    const QByteArray expression = textOf(idExpr);
+
+                    const QList<LookupItem> candidates = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
+                    addVirtualMethodUsage(candidates, idExpr->name, argumentCount);
+                }
+            }
+        }
+
+        accept(ast->expression_list);
+    }
+
+    return false;
+}
+
+QByteArray CheckSymbols::textOf(AST *ast) const
+{
+    const Token start = tokenAt(ast->firstToken());
+    const Token end = tokenAt(ast->lastToken() - 1);
+    const QByteArray text = _doc->source().mid(start.begin(), end.end() - start.begin());
+    return text;
+}
+
 void CheckSymbols::checkNamespace(NameAST *name)
 {
     if (! name)
@@ -573,6 +661,21 @@ bool CheckSymbols::visit(FunctionDefinitionAST *ast)
     _functionDefinitionStack.append(ast);
 
     accept(ast->decl_specifier_list);
+
+    if (ast->declarator && ! ast->symbol->isGenerated()) {
+        Function *fun = ast->symbol;
+        if (NameAST *declId = declaratorId(ast->declarator)) {
+            if (QualifiedNameAST *q = declId->asQualifiedName())
+                declId = q->unqualified_name;
+
+            if (fun->isVirtual()) {
+                addVirtualMethodUsage(declId);
+            } else if (maybeVirtualMethod(fun->name())) {
+                addVirtualMethodUsage(_context.lookup(fun->name(), fun->scope()), declId, fun->argumentCount());
+            }
+        }
+    }
+
     accept(ast->declarator);
     accept(ast->ctor_initializer);
     accept(ast->function_body);
@@ -687,8 +790,61 @@ void CheckSymbols::addMemberUsage(const QList<LookupItem> &candidates, NameAST *
 
         const Use use(line, column, length, Use::Field);
         addUsage(use);
-        //Overview oo;
-        //qDebug() << "added use" << oo(ast->name) << line << column << length;
+        break;
+    }
+}
+
+void CheckSymbols::addVirtualMethodUsage(NameAST *ast)
+{
+    if (! ast)
+        return;
+
+    unsigned startToken = ast->firstToken();
+    if (DestructorNameAST *dtor = ast->asDestructorName())
+        startToken = dtor->identifier_token;
+
+    const Token &tok = tokenAt(startToken);
+    if (tok.generated())
+        return;
+
+    unsigned line, column;
+    getTokenStartPosition(startToken, &line, &column);
+    const unsigned length = tok.length();
+
+    const Use use(line, column, length, Use::VirtualMethod);
+    addUsage(use);
+}
+
+void CheckSymbols::addVirtualMethodUsage(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount)
+{
+    unsigned startToken = ast->firstToken();
+    if (DestructorNameAST *dtor = ast->asDestructorName())
+        startToken = dtor->identifier_token;
+
+    const Token &tok = tokenAt(startToken);
+    if (tok.generated())
+        return;
+
+    unsigned line, column;
+    getTokenStartPosition(startToken, &line, &column);
+    const unsigned length = tok.length();
+
+    foreach (const LookupItem &r, candidates) {
+        Symbol *c = r.declaration();
+        if (! c)
+            continue;
+
+        Function *funTy = r.type()->asFunctionType();
+        if (! funTy)
+            continue;
+        if (! funTy->isVirtual())
+            continue;
+        else if (argumentCount < funTy->minimumArgumentCount())
+            continue;
+
+        const Use use(line, column, length, Use::VirtualMethod);
+        addUsage(use);
+        break;
     }
 }
 
@@ -723,6 +879,30 @@ Scope *CheckSymbols::findScope(AST *ast) const
     return scope;
 }
 
+NameAST *CheckSymbols::declaratorId(DeclaratorAST *ast) const
+{
+    if (ast && ast->core_declarator) {
+        if (NestedDeclaratorAST *nested = ast->core_declarator->asNestedDeclarator())
+            return declaratorId(nested->declarator);
+        else if (DeclaratorIdAST *declId = ast->core_declarator->asDeclaratorId()) {
+            return declId->name;
+        }
+    }
+
+    return 0;
+}
+
+bool CheckSymbols::maybeVirtualMethod(const Name *name) const
+{
+    if (const Identifier *ident = name->identifier()) {
+        const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
+        if (_potentialVirtualMethods.contains(id))
+            return true;
+    }
+
+    return false;
+}
+
 void CheckSymbols::flush()
 {
     _flushRequested = false;
diff --git a/src/plugins/cppeditor/cppchecksymbols.h b/src/plugins/cppeditor/cppchecksymbols.h
index 8b3418fc4584704324bd94b5f953dd660dad1eff..5047e839a986e1c33937de9afbb125c15c5f2ab3 100644
--- a/src/plugins/cppeditor/cppchecksymbols.h
+++ b/src/plugins/cppeditor/cppchecksymbols.h
@@ -93,6 +93,8 @@ protected:
     bool warning(unsigned line, unsigned column, const QString &text, unsigned length = 0);
     bool warning(AST *ast, const QString &text);
 
+    QByteArray textOf(AST *ast) const;
+
     void checkName(NameAST *ast, Scope *scope = 0);
     void checkNamespace(NameAST *name);
     void addUsage(ClassOrNamespace *b, NameAST *ast);
@@ -101,6 +103,10 @@ protected:
 
     void checkMemberName(NameAST *ast);
     void addMemberUsage(const QList<LookupItem> &candidates, NameAST *ast);
+    void addVirtualMethodUsage(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount);
+    void addVirtualMethodUsage(NameAST *ast);
+
+    bool maybeVirtualMethod(const Name *name) const;
 
     virtual bool preVisit(AST *);
 
@@ -122,9 +128,12 @@ protected:
 
     virtual bool visit(FunctionDefinitionAST *ast);
     virtual bool visit(MemberAccessAST *ast);
+    virtual bool visit(CallAST *ast);
 
     virtual bool visit(MemInitializerAST *ast);
 
+    NameAST *declaratorId(DeclaratorAST *ast) const;
+
     unsigned startOfTemplateDeclaration(TemplateDeclarationAST *ast) const;
     Scope *findScope(AST *ast) const;
 
@@ -138,6 +147,7 @@ private:
     QList<Document::DiagnosticMessage> _diagnosticMessages;
     QSet<QByteArray> _potentialTypes;
     QSet<QByteArray> _potentialMembers;
+    QSet<QByteArray> _potentialVirtualMethods;
     QList<ScopedSymbol *> _scopes;
     QList<TemplateDeclarationAST *> _templateDeclarationStack;
     QList<FunctionDefinitionAST *> _functionDefinitionStack;
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index 319d2db63c9d26adefb5b97eb0a033519b8c6a6b..7deb214b17ce2c8933920527ff23d629f8a1f367 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -968,6 +968,9 @@ void CPPEditor::highlightTypeUsages(int from, int to)
     Q_ASSERT(!chunks.isEmpty());
     QTextBlock b = doc->findBlockByNumber(m_nextHighlightBlockNumber);
 
+    QTextCharFormat virtualMethodFormat; // ### hardcoded;
+    virtualMethodFormat.setFontItalic(true);
+
     QMapIterator<int, QVector<SemanticInfo::Use> > it(chunks);
     while (b.isValid() && it.hasNext()) {
         it.next();
@@ -997,6 +1000,10 @@ void CPPEditor::highlightTypeUsages(int from, int to)
                 formatRange.format = m_localFormat;
                 break;
 
+            case SemanticInfo::Use::VirtualMethod:
+                formatRange.format = virtualMethodFormat;
+                break;
+
             default:
                 continue;
             }
diff --git a/src/plugins/cppeditor/cppsemanticinfo.h b/src/plugins/cppeditor/cppsemanticinfo.h
index 3ea662bdbbe3049a054e864bc61aa4729574bf0c..59768a6f1a945911416522d87691cf1a8c1b462f 100644
--- a/src/plugins/cppeditor/cppsemanticinfo.h
+++ b/src/plugins/cppeditor/cppsemanticinfo.h
@@ -51,7 +51,8 @@ public:
         enum {
             Type = 0,
             Local,
-            Field
+            Field,
+            VirtualMethod
         };
 
         Use(unsigned line = 0, unsigned column = 0, unsigned length = 0, unsigned kind = Type)
diff --git a/src/shared/cplusplus/Symbols.cpp b/src/shared/cplusplus/Symbols.cpp
index e82a60ae199e92cd9bd25bf0d388412b67f61d6c..c1dcec44a4ed16fb6003a1312e8989b21236711b 100644
--- a/src/shared/cplusplus/Symbols.cpp
+++ b/src/shared/cplusplus/Symbols.cpp
@@ -352,6 +352,20 @@ bool Function::hasArguments() const
               (argumentCount() == 1 && argumentAt(0)->type()->isVoidType()));
 }
 
+unsigned Function::minimumArgumentCount() const
+{
+    unsigned index = 0;
+
+    for (; index < _arguments->symbolCount(); ++index) {
+        if (Argument *arg = _arguments->symbolAt(index)->asArgument()) {
+            if (arg->hasInitializer())
+                break;
+        }
+    }
+
+    return index;
+}
+
 bool Function::isVirtual() const
 { return f._isVirtual; }
 
diff --git a/src/shared/cplusplus/Symbols.h b/src/shared/cplusplus/Symbols.h
index 2a90fd0cc0306b5712e4f9385fea450129a1d67b..0f5d8d83745c1b215d80c9ed925e34945de5c98f 100644
--- a/src/shared/cplusplus/Symbols.h
+++ b/src/shared/cplusplus/Symbols.h
@@ -360,6 +360,7 @@ public:
 
     /** Convenience function that returns whether the function receives any arguments. */
     bool hasArguments() const;
+    unsigned minimumArgumentCount() const;
 
     bool isVirtual() const;
     void setVirtual(bool isVirtual);