CppEditor: Fix "Switch Method Decl/Def" for cursor on return type

If the cursor is on the return type, Document::lastVisibleSymbol()
returns the function defined before the current function definition,
which is unfavorable for "Switch Method Decl/Def".

Fixed by using ASTPath instead of Document::lastVisibleSymbol().

Task-Number: QTCREATORBUG-9206

Change-Id: I94aba2fdbb437c6007f328f31deee7ae363364e2
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Nikolai Kosjar
2013-04-26 17:35:55 +02:00
parent 49e27b35fc
commit ed4b202774
3 changed files with 85 additions and 42 deletions

View File

@@ -1180,60 +1180,70 @@ void CPPEditorWidget::finishHighlightSymbolUsages()
void CPPEditorWidget::switchDeclarationDefinition(bool inNextSplit)
{
if (! m_modelManager)
if (!m_modelManager)
return;
const Snapshot snapshot = m_modelManager->snapshot();
if (!m_lastSemanticInfo.doc)
return;
if (Document::Ptr thisDocument = snapshot.document(editorDocument()->fileName())) {
int line = 0, positionInBlock = 0;
convertPosition(position(), &line, &positionInBlock);
// Find function declaration or definition under cursor
Function *functionDefinitionSymbol = 0;
Symbol *functionDeclarationSymbol = 0;
Symbol *lastVisibleSymbol = thisDocument->lastVisibleSymbolAt(line, positionInBlock + 1);
if (! lastVisibleSymbol)
return;
ASTPath astPathFinder(m_lastSemanticInfo.doc);
const QList<AST *> astPath = astPathFinder(textCursor());
Function *function = lastVisibleSymbol->asFunction();
if (! function)
function = lastVisibleSymbol->enclosingFunction();
CPPEditorWidget::Link symbolLink;
if (function) {
LookupContext context(thisDocument, snapshot);
Function *functionDefinition = function->asFunction();
ClassOrNamespace *binding = context.lookupType(functionDefinition);
const QList<LookupItem> declarations = context.lookup(functionDefinition->name(),
functionDefinition->enclosingScope());
QList<Symbol *> best;
foreach (const LookupItem &r, declarations) {
if (Symbol *decl = r.declaration()) {
if (Function *funTy = decl->type()->asFunctionType()) {
if (funTy->isEqualTo(function)) {
if (decl != function && binding == r.binding())
best.prepend(decl);
else
best.append(decl);
}
for (int i = 0, size = astPath.size(); i < size; ++i) {
AST *ast = astPath.at(i);
if (FunctionDefinitionAST *functionDefinitionAST = ast->asFunctionDefinition()) {
if ((functionDefinitionSymbol = functionDefinitionAST->symbol))
break; // Function definition found!
} else if (SimpleDeclarationAST *simpleDeclaration = ast->asSimpleDeclaration()) {
if (List<Symbol *> *symbols = simpleDeclaration->symbols) {
if (Symbol *symbol = symbols->value) {
if (symbol->isDeclaration() && symbol->type()->isFunctionType()) {
functionDeclarationSymbol = symbol;
break; // Function declaration found!
}
}
}
if (best.isEmpty())
return;
}
}
symbolLink = linkToSymbol(best.first());
} else if (lastVisibleSymbol
&& lastVisibleSymbol->isDeclaration()
&& lastVisibleSymbol->type()->isFunctionType()) {
symbolLink = linkToSymbol(
symbolFinder()->findMatchingDefinition(lastVisibleSymbol, snapshot));
// Link to function definition/declaration
CPPEditorWidget::Link symbolLink;
if (functionDeclarationSymbol) {
symbolLink = linkToSymbol(symbolFinder()
->findMatchingDefinition(functionDeclarationSymbol, modelManager()->snapshot()));
} else if (functionDefinitionSymbol) {
const Snapshot snapshot = m_modelManager->snapshot();
LookupContext context(m_lastSemanticInfo.doc, snapshot);
ClassOrNamespace *binding = context.lookupType(functionDefinitionSymbol);
const QList<LookupItem> declarations = context.lookup(functionDefinitionSymbol->name(),
functionDefinitionSymbol->enclosingScope());
QList<Symbol *> best;
foreach (const LookupItem &r, declarations) {
if (Symbol *decl = r.declaration()) {
if (Function *funTy = decl->type()->asFunctionType()) {
if (funTy->isEqualTo(functionDefinitionSymbol)) {
if (decl != functionDefinitionSymbol && binding == r.binding())
best.prepend(decl);
else
best.append(decl);
}
}
}
}
if (symbolLink.hasValidTarget())
openCppEditorAt(symbolLink, inNextSplit != alwaysOpenLinksInNextSplit());
if (best.isEmpty())
return;
symbolLink = linkToSymbol(best.first());
}
// Open Editor at link position
if (symbolLink.hasValidTarget())
openCppEditorAt(symbolLink, inNextSplit != alwaysOpenLinksInNextSplit());
}
static inline LookupItem skipForwardDeclarations(const QList<LookupItem> &resolvedSymbols)