QString AbstractEditorSupport::functionAt(const CppModelManagerInterface *modelManager,
                                          const QString &fileName,
                                          int line, int column)
{
    const CPlusPlus::Snapshot snapshot = modelManager->snapshot();
    const CPlusPlus::Document::Ptr document = snapshot.document(fileName);
    if (!document)
        return QString();
    if (const CPlusPlus::Symbol *symbol = document->lastVisibleSymbolAt(line, column))
        if (const CPlusPlus::Scope *scope = symbol->enclosingScope())
            if (const CPlusPlus::Scope *functionScope = scope->enclosingFunction())
                if (const CPlusPlus::Symbol *function = functionScope) {
                    const CPlusPlus::Overview o;
                    QString rc = o.prettyName(function->name());
                    // Prepend namespace "Foo::Foo::foo()" up to empty root namespace
                    for (const CPlusPlus::Symbol *owner = function->enclosingNamespace();
                         owner; owner = owner->enclosingNamespace()) {
                        const QString name = o.prettyName(owner->name());
                        if (name.isEmpty()) {
                            break;
                        } else {
                            rc.prepend(QLatin1String("::"));
                            rc.prepend(name);
                        }
                    }
                    return rc;
                }
    return QString();
}
CPlusPlus::Function *CppFunction::function(int line, int column, const QString &fileName)
{
    const CPlusPlus::Snapshot snapshot = CppTools::CppModelManagerInterface::instance()->snapshot();
    const CPlusPlus::Document::Ptr document = snapshot.document(fileName);
    if (!document)
        return 0;

    CPlusPlus::Symbol *symbol = document->lastVisibleSymbolAt(line, column);
    if (!symbol)
        return 0;

    // Find the enclosing function scope (which might be several levels up, or we might be standing on it)
    CPlusPlus::Scope *scope;
    if (symbol->isScope())
        scope = symbol->asScope();
    else
        scope = symbol->enclosingScope();

    while (scope && !scope->isFunction() )
        scope = scope->enclosingScope();

    if (!scope)
        return 0;

    return scope->asFunction();
}
// Inline helper with integer error return codes.
static inline
int getUninitializedVariablesI(const CPlusPlus::Snapshot &snapshot,
                               const QString &functionName,
                               const QString &file,
                               int line,
                               QStringList *uninitializedVariables)
{
    uninitializedVariables->clear();
    // Find document
    if (snapshot.isEmpty() || functionName.isEmpty() || file.isEmpty() || line < 1)
        return 1;
    const CPlusPlus::Snapshot::const_iterator docIt = snapshot.find(file);
    if (docIt == snapshot.end())
        return 2;
    const CPlusPlus::Document::Ptr doc = docIt.value();
    // Look at symbol at line and find its function. Either it is the
    // function itself or some expression/variable.
    const CPlusPlus::Symbol *symbolAtLine = doc->lastVisibleSymbolAt(line, 0);
    if (!symbolAtLine)
        return 4;
    // First figure out the function to do a safety name check
    // and the innermost scope at cursor position
    const CPlusPlus::Function *function = 0;
    const CPlusPlus::Scope *innerMostScope = 0;
    if (symbolAtLine->isFunction()) {
        function = symbolAtLine->asFunction();
        if (function->memberCount() == 1) // Skip over function block
            if (CPlusPlus::Block *block = function->memberAt(0)->asBlock())
                innerMostScope = block;
    } else {
        if (const CPlusPlus::Scope *functionScope = symbolAtLine->enclosingFunction()) {
            function = functionScope->asFunction();
            innerMostScope = symbolAtLine->isBlock() ?
                             symbolAtLine->asBlock() :
                             symbolAtLine->enclosingBlock();
        }
    }
    if (!function || !innerMostScope)
        return 7;
    // Compare function names with a bit off fuzz,
    // skipping modules from a CDB symbol "lib!foo" or namespaces
    // that the code model does not show at this point
    CPlusPlus::Overview overview;
    const QString name = overview.prettyName(function->name());
    if (!functionName.endsWith(name))
        return 11;
    if (functionName.size() > name.size()) {
        const char previousChar = functionName.at(functionName.size() - name.size() - 1).toLatin1();
        if (previousChar != ':' && previousChar != '!' )
            return 11;
    }
    // Starting from the innermost block scope, collect declarations.
    SeenHash seenHash;
    blockRecursion(overview, innerMostScope, line, uninitializedVariables, &seenHash);
    return 0;
}