C++ function link: Disable function links on name change.

Change-Id: Ib5e3a3a381568347a7a465f956f7daad15f10ab0
Reviewed-on: http://codereview.qt.nokia.com/3596
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
This commit is contained in:
Christian Kamm
2011-08-25 13:22:21 +02:00
parent bd5a1a9bce
commit 3dcf168165
3 changed files with 49 additions and 25 deletions

View File

@@ -2161,10 +2161,11 @@ void CPPEditorWidget::updateFunctionDeclDefLink()
{ {
const int pos = textCursor().selectionStart(); const int pos = textCursor().selectionStart();
// if there's already a link, abort it if the cursor is outside // if there's already a link, abort it if the cursor is outside or the name changed
if (m_declDefLink if (m_declDefLink
&& (pos < m_declDefLink->linkSelection.selectionStart() && (pos < m_declDefLink->linkSelection.selectionStart()
|| pos > m_declDefLink->linkSelection.selectionEnd())) { || pos > m_declDefLink->linkSelection.selectionEnd()
|| m_declDefLink->nameSelection.selectedText() != m_declDefLink->nameInitial)) {
abortDeclDefLink(); abortDeclDefLink();
return; return;
} }

View File

@@ -64,9 +64,14 @@ FunctionDeclDefLinkFinder::FunctionDeclDefLinkFinder(QObject *parent)
void FunctionDeclDefLinkFinder::onFutureDone() void FunctionDeclDefLinkFinder::onFutureDone()
{ {
QSharedPointer<FunctionDeclDefLink> link = m_watcher.result(); QSharedPointer<FunctionDeclDefLink> link = m_watcher.result();
if (link) if (link) {
link->linkSelection = m_scannedSelection; link->linkSelection = m_scannedSelection;
link->nameSelection = m_nameSelection;
if (m_nameSelection.selectedText() != link->nameInitial)
link.clear();
}
m_scannedSelection = QTextCursor(); m_scannedSelection = QTextCursor();
m_nameSelection = QTextCursor();
if (link) if (link)
emit foundLink(link); emit foundLink(link);
} }
@@ -79,7 +84,8 @@ QTextCursor FunctionDeclDefLinkFinder::scannedSelection() const
// parent is either a FunctionDefinitionAST or a SimpleDeclarationAST // parent is either a FunctionDefinitionAST or a SimpleDeclarationAST
// line and column are 1-based // line and column are 1-based
static bool findDeclOrDef(const Document::Ptr &doc, int line, int column, static bool findDeclOrDef(const Document::Ptr &doc, int line, int column,
DeclarationAST **parent, FunctionDeclaratorAST **funcDecl) DeclarationAST **parent, DeclaratorAST **decl,
FunctionDeclaratorAST **funcDecl)
{ {
QList<AST *> path = ASTPath(doc)(line, column); QList<AST *> path = ASTPath(doc)(line, column);
@@ -89,29 +95,29 @@ static bool findDeclOrDef(const Document::Ptr &doc, int line, int column,
// with a FunctionDeclarator postfix // with a FunctionDeclarator postfix
FunctionDefinitionAST *funcDef = 0; FunctionDefinitionAST *funcDef = 0;
SimpleDeclarationAST *simpleDecl = 0; SimpleDeclarationAST *simpleDecl = 0;
DeclaratorAST *decl = 0; *decl = 0;
for (int i = path.size() - 1; i > 0; --i) { for (int i = path.size() - 1; i > 0; --i) {
AST *ast = path.at(i); AST *ast = path.at(i);
if (ast->asCompoundStatement() || ast->asCtorInitializer()) if (ast->asCompoundStatement() || ast->asCtorInitializer())
break; break;
if ((funcDef = ast->asFunctionDefinition()) != 0) { if ((funcDef = ast->asFunctionDefinition()) != 0) {
*parent = funcDef; *parent = funcDef;
decl = funcDef->declarator; *decl = funcDef->declarator;
break; break;
} }
if ((simpleDecl = ast->asSimpleDeclaration()) != 0) { if ((simpleDecl = ast->asSimpleDeclaration()) != 0) {
*parent = simpleDecl; *parent = simpleDecl;
if (!simpleDecl->declarator_list || !simpleDecl->declarator_list->value) if (!simpleDecl->declarator_list || !simpleDecl->declarator_list->value)
break; break;
decl = simpleDecl->declarator_list->value; *decl = simpleDecl->declarator_list->value;
break; break;
} }
} }
if (!*parent || !decl) if (!*parent || !*decl)
return false; return false;
if (!decl->postfix_declarator_list || !decl->postfix_declarator_list->value) if (!(*decl)->postfix_declarator_list || !(*decl)->postfix_declarator_list->value)
return false; return false;
*funcDecl = decl->postfix_declarator_list->value->asFunctionDeclarator(); *funcDecl = (*decl)->postfix_declarator_list->value->asFunctionDeclarator();
return *funcDecl; return *funcDecl;
} }
@@ -130,6 +136,19 @@ static void declDefLinkStartEnd(const CppTools::CppRefactoringFileConstPtr &file
*end = file->endOf(funcDecl->rparen_token); *end = file->endOf(funcDecl->rparen_token);
} }
static DeclaratorIdAST *getDeclaratorId(DeclaratorAST *declarator)
{
if (!declarator || !declarator->core_declarator)
return 0;
if (DeclaratorIdAST *id = declarator->core_declarator->asDeclaratorId()) {
return id;
}
if (NestedDeclaratorAST *nested = declarator->core_declarator->asNestedDeclarator()) {
return getDeclaratorId(nested->declarator);
}
return 0;
}
static QSharedPointer<FunctionDeclDefLink> findLinkHelper(QSharedPointer<FunctionDeclDefLink> link, CppTools::CppRefactoringChanges changes) static QSharedPointer<FunctionDeclDefLink> findLinkHelper(QSharedPointer<FunctionDeclDefLink> link, CppTools::CppRefactoringChanges changes)
{ {
QSharedPointer<FunctionDeclDefLink> noResult; QSharedPointer<FunctionDeclDefLink> noResult;
@@ -160,8 +179,9 @@ static QSharedPointer<FunctionDeclDefLink> findLinkHelper(QSharedPointer<Functio
DeclarationAST *targetParent = 0; DeclarationAST *targetParent = 0;
FunctionDeclaratorAST *targetFuncDecl = 0; FunctionDeclaratorAST *targetFuncDecl = 0;
DeclaratorAST *targetDeclarator = 0;
if (!findDeclOrDef(targetFile->cppDocument(), target->line(), target->column(), if (!findDeclOrDef(targetFile->cppDocument(), target->line(), target->column(),
&targetParent, &targetFuncDecl)) &targetParent, &targetDeclarator, &targetFuncDecl))
return noResult; return noResult;
// the parens are necessary for finding good places for changes // the parens are necessary for finding good places for changes
@@ -191,7 +211,9 @@ void FunctionDeclDefLinkFinder::startFindLinkAt(
// check if cursor is on function decl/def // check if cursor is on function decl/def
DeclarationAST *parent = 0; DeclarationAST *parent = 0;
FunctionDeclaratorAST *funcDecl = 0; FunctionDeclaratorAST *funcDecl = 0;
if (!findDeclOrDef(doc, cursor.blockNumber() + 1, cursor.columnNumber() + 1, &parent, &funcDecl)) DeclaratorAST *declarator = 0;
if (!findDeclOrDef(doc, cursor.blockNumber() + 1, cursor.columnNumber() + 1,
&parent, &declarator, &funcDecl))
return; return;
// find the start/end offsets // find the start/end offsets
@@ -214,8 +236,16 @@ void FunctionDeclDefLinkFinder::startFindLinkAt(
m_scannedSelection.setPosition(start, QTextCursor::KeepAnchor); m_scannedSelection.setPosition(start, QTextCursor::KeepAnchor);
m_scannedSelection.setKeepPositionOnInsert(true); m_scannedSelection.setKeepPositionOnInsert(true);
// build selection for the name
DeclaratorIdAST *declId = getDeclaratorId(declarator);
m_nameSelection = cursor;
m_nameSelection.setPosition(sourceFile->endOf(declId));
m_nameSelection.setPosition(sourceFile->startOf(declId), QTextCursor::KeepAnchor);
m_nameSelection.setKeepPositionOnInsert(true);
// set up a base result // set up a base result
QSharedPointer<FunctionDeclDefLink> result(new FunctionDeclDefLink); QSharedPointer<FunctionDeclDefLink> result(new FunctionDeclDefLink);
result->nameInitial = m_nameSelection.selectedText();
result->sourceDocument = doc; result->sourceDocument = doc;
result->sourceFunction = funcDecl->symbol; result->sourceFunction = funcDecl->symbol;
result->sourceDeclaration = parent; result->sourceDeclaration = parent;
@@ -255,19 +285,6 @@ static bool namesEqual(const Name *n1, const Name *n2)
return n1 == n2 || (n1 && n2 && n1->isEqualTo(n2)); return n1 == n2 || (n1 && n2 && n1->isEqualTo(n2));
} }
static DeclaratorIdAST *getDeclaratorId(DeclaratorAST *declarator)
{
if (!declarator || !declarator->core_declarator)
return 0;
if (DeclaratorIdAST *id = declarator->core_declarator->asDeclaratorId()) {
return id;
}
if (NestedDeclaratorAST *nested = declarator->core_declarator->asNestedDeclarator()) {
return getDeclaratorId(nested->declarator);
}
return 0;
}
void FunctionDeclDefLink::apply(CPPEditorWidget *editor, bool jumpToMatch) void FunctionDeclDefLink::apply(CPPEditorWidget *editor, bool jumpToMatch)
{ {
Snapshot snapshot = editor->semanticInfo().snapshot; Snapshot snapshot = editor->semanticInfo().snapshot;

View File

@@ -71,6 +71,7 @@ private slots:
private: private:
QTextCursor m_scannedSelection; QTextCursor m_scannedSelection;
QTextCursor m_nameSelection;
QFutureWatcher<QSharedPointer<FunctionDeclDefLink> > m_watcher; QFutureWatcher<QSharedPointer<FunctionDeclDefLink> > m_watcher;
}; };
@@ -92,6 +93,11 @@ public:
Utils::ChangeSet changes(const CPlusPlus::Snapshot &snapshot, int targetOffset = -1); Utils::ChangeSet changes(const CPlusPlus::Snapshot &snapshot, int targetOffset = -1);
QTextCursor linkSelection; QTextCursor linkSelection;
// stored to allow aborting when the name is changed
QTextCursor nameSelection;
QString nameInitial;
// 1-based line and column // 1-based line and column
unsigned targetLine; unsigned targetLine;
unsigned targetColumn; unsigned targetColumn;