forked from qt-creator/qt-creator
		
	Improved switching between method declarationand definition.
Reviewed-by: Roberto Raggi
This commit is contained in:
		@@ -49,6 +49,7 @@
 | 
			
		||||
#include <ASTVisitor.h>
 | 
			
		||||
#include <SymbolVisitor.h>
 | 
			
		||||
#include <TranslationUnit.h>
 | 
			
		||||
#include <cplusplus/ASTPath.h>
 | 
			
		||||
#include <cplusplus/ExpressionUnderCursor.h>
 | 
			
		||||
#include <cplusplus/TypeOfExpression.h>
 | 
			
		||||
#include <cplusplus/Overview.h>
 | 
			
		||||
@@ -1172,6 +1173,139 @@ static inline LookupItem skipForwardDeclarations(const QList<LookupItem> &resolv
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
QList<Declaration *> findMatchingDeclaration(const LookupContext &context,
 | 
			
		||||
                                             Function *functionType)
 | 
			
		||||
{
 | 
			
		||||
    QList<Declaration *> result;
 | 
			
		||||
 | 
			
		||||
    Scope *enclosingScope = functionType->enclosingScope();
 | 
			
		||||
    while (! (enclosingScope->isNamespace() || enclosingScope->isClass()))
 | 
			
		||||
        enclosingScope = enclosingScope->enclosingScope();
 | 
			
		||||
    Q_ASSERT(enclosingScope != 0);
 | 
			
		||||
 | 
			
		||||
    const Name *functionName = functionType->name();
 | 
			
		||||
    if (! functionName)
 | 
			
		||||
        return result; // anonymous function names are not valid c++
 | 
			
		||||
 | 
			
		||||
    ClassOrNamespace *binding = 0;
 | 
			
		||||
    const QualifiedNameId *qName = functionName->asQualifiedNameId();
 | 
			
		||||
    if (qName) {
 | 
			
		||||
        if (qName->base())
 | 
			
		||||
            binding = context.lookupType(qName->base(), enclosingScope);
 | 
			
		||||
        functionName = qName->name();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!binding) { // declaration for a global function
 | 
			
		||||
        binding = context.lookupType(enclosingScope);
 | 
			
		||||
 | 
			
		||||
        if (!binding)
 | 
			
		||||
            return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Identifier *funcId = functionName->identifier();
 | 
			
		||||
    if (!funcId) // E.g. operator, which we might be able to handle in the future...
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    QList<Declaration *> good, better, best;
 | 
			
		||||
 | 
			
		||||
    foreach (Symbol *s, binding->symbols()) {
 | 
			
		||||
        Class *matchingClass = s->asClass();
 | 
			
		||||
        if (!matchingClass)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        for (Symbol *s = matchingClass->find(funcId); s; s = s->next()) {
 | 
			
		||||
            if (! s->name())
 | 
			
		||||
                continue;
 | 
			
		||||
            else if (! funcId->isEqualTo(s->identifier()))
 | 
			
		||||
                continue;
 | 
			
		||||
            else if (! s->type()->isFunctionType())
 | 
			
		||||
                continue;
 | 
			
		||||
            else if (Declaration *decl = s->asDeclaration()) {
 | 
			
		||||
                if (Function *declFunTy = decl->type()->asFunctionType()) {
 | 
			
		||||
                    if (functionType->isEqualTo(declFunTy))
 | 
			
		||||
                        best.prepend(decl);
 | 
			
		||||
                    else if (functionType->argumentCount() == declFunTy->argumentCount() && result.isEmpty())
 | 
			
		||||
                        better.prepend(decl);
 | 
			
		||||
                    else
 | 
			
		||||
                        good.append(decl);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result.append(best);
 | 
			
		||||
    result.append(better);
 | 
			
		||||
    result.append(good);
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // end of anonymous namespace
 | 
			
		||||
 | 
			
		||||
CPPEditor::Link CPPEditor::attemptFuncDeclDef(const QTextCursor &cursor, const Document::Ptr &doc, Snapshot snapshot) const
 | 
			
		||||
{
 | 
			
		||||
    snapshot.insert(doc);
 | 
			
		||||
 | 
			
		||||
    Link result;
 | 
			
		||||
 | 
			
		||||
    QList<AST *> path = ASTPath(doc)(cursor);
 | 
			
		||||
 | 
			
		||||
    if (path.size() < 5)
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    NameAST *name = path.last()->asName();
 | 
			
		||||
    if (!name)
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    if (QualifiedNameAST *qName = path.at(path.size() - 2)->asQualifiedName()) {
 | 
			
		||||
        // TODO: check which part of the qualified name we're on
 | 
			
		||||
        if (qName->unqualified_name != name)
 | 
			
		||||
            return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    AST *declParent = 0;
 | 
			
		||||
    DeclaratorAST *decl = 0;
 | 
			
		||||
    for (int i = path.size() - 2; i > 0; --i) {
 | 
			
		||||
        if ((decl = path.at(i)->asDeclarator()) != 0) {
 | 
			
		||||
            declParent = path.at(i - 1);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (!decl || !declParent)
 | 
			
		||||
        return result;
 | 
			
		||||
    if (!decl->postfix_declarator_list || !decl->postfix_declarator_list->value)
 | 
			
		||||
        return result;
 | 
			
		||||
    FunctionDeclaratorAST *funcDecl = decl->postfix_declarator_list->value->asFunctionDeclarator();
 | 
			
		||||
    if (!funcDecl)
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    Symbol *target = 0;
 | 
			
		||||
    if (FunctionDefinitionAST *funDef = declParent->asFunctionDefinition()) {
 | 
			
		||||
        QList<Declaration *> candidates = findMatchingDeclaration(LookupContext(doc, snapshot),
 | 
			
		||||
                                                                  funDef->symbol);
 | 
			
		||||
        if (!candidates.isEmpty()) // TODO: improve disambiguation
 | 
			
		||||
            target = candidates.first();
 | 
			
		||||
    } else if (declParent->asSimpleDeclaration()) {
 | 
			
		||||
        target = snapshot.findMatchingDefinition(funcDecl->symbol);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (target) {
 | 
			
		||||
        result = linkToSymbol(target);
 | 
			
		||||
 | 
			
		||||
        unsigned startLine, startColumn, endLine, endColumn;
 | 
			
		||||
        doc->translationUnit()->getTokenStartPosition(name->firstToken(), &startLine, &startColumn);
 | 
			
		||||
        doc->translationUnit()->getTokenEndPosition(name->lastToken() - 1, &endLine, &endColumn);
 | 
			
		||||
 | 
			
		||||
        QTextDocument *textDocument = cursor.document();
 | 
			
		||||
        result.begin = textDocument->findBlockByNumber(startLine - 1).position() + startColumn - 1;
 | 
			
		||||
        result.end = textDocument->findBlockByNumber(endLine - 1).position() + endColumn - 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
 | 
			
		||||
                                      bool resolveTarget)
 | 
			
		||||
{
 | 
			
		||||
@@ -1181,6 +1315,14 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor,
 | 
			
		||||
        return link;
 | 
			
		||||
 | 
			
		||||
    const Snapshot snapshot = m_modelManager->snapshot();
 | 
			
		||||
 | 
			
		||||
    if (m_lastSemanticInfo.doc){
 | 
			
		||||
        Link l = attemptFuncDeclDef(cursor, m_lastSemanticInfo.doc, snapshot);
 | 
			
		||||
        if (l.isValid()) {
 | 
			
		||||
            return l;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int lineNumber = 0, positionInBlock = 0;
 | 
			
		||||
    convertPosition(cursor.position(), &lineNumber, &positionInBlock);
 | 
			
		||||
    Document::Ptr doc = snapshot.document(file()->fileName());
 | 
			
		||||
@@ -1363,7 +1505,7 @@ void CPPEditor::jumpToDefinition()
 | 
			
		||||
    openLink(findLinkAt(textCursor()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Symbol *CPPEditor::findDefinition(Symbol *symbol, const Snapshot &snapshot)
 | 
			
		||||
Symbol *CPPEditor::findDefinition(Symbol *symbol, const Snapshot &snapshot) const
 | 
			
		||||
{
 | 
			
		||||
    if (symbol->isFunction())
 | 
			
		||||
        return 0; // symbol is a function definition.
 | 
			
		||||
 
 | 
			
		||||
@@ -237,7 +237,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    void markSymbols(const QTextCursor &tc, const SemanticInfo &info);
 | 
			
		||||
    bool sortedOutline() const;
 | 
			
		||||
    CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
 | 
			
		||||
    CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot) const;
 | 
			
		||||
 | 
			
		||||
    TextEditor::ITextEditor *openCppEditorAt(const QString &fileName, int line,
 | 
			
		||||
                                             int column = 0);
 | 
			
		||||
@@ -254,6 +254,9 @@ private:
 | 
			
		||||
    void finishRename();
 | 
			
		||||
    void abortRename();
 | 
			
		||||
 | 
			
		||||
    Link attemptFuncDeclDef(const QTextCursor &cursor,
 | 
			
		||||
                            const CPlusPlus::Document::Ptr &doc,
 | 
			
		||||
                            CPlusPlus::Snapshot snapshot) const;
 | 
			
		||||
    Link findLinkAt(const QTextCursor &, bool resolveTarget = true);
 | 
			
		||||
    bool openCppEditorAt(const Link &);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user