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