diff --git a/src/plugins/cppeditor/cppquickfix.cpp b/src/plugins/cppeditor/cppquickfix.cpp index 3efd6f81af79cec635adcba601b73022661eaf9e..b9a39f2dc6191417a38ed21b9aca981e28d73a35 100644 --- a/src/plugins/cppeditor/cppquickfix.cpp +++ b/src/plugins/cppeditor/cppquickfix.cpp @@ -159,6 +159,117 @@ private: BinaryExpressionAST *pattern; }; +class SplitSimpleDeclarationOp: public QuickFixOperation +{ +public: + SplitSimpleDeclarationOp(Document::Ptr doc, const Snapshot &snapshot, CPPEditor *editor) + : QuickFixOperation(doc, snapshot), declaration(0), editor(editor) + {} + + virtual QString description() const + { + return QLatin1String("Split declaration"); // ### tr? + } + + bool checkDeclaration(SimpleDeclarationAST *declaration) const + { + if (! declaration->decl_specifier_list) + return false; + + for (SpecifierListAST *it = declaration->decl_specifier_list; it; it = it->next) { + SpecifierAST *specifier = it->value; + + if (specifier->asEnumSpecifier() != 0) + return false; + + else if (specifier->asClassSpecifier() != 0) + return false; + } + + if (! declaration->declarator_list) + return false; + + else if (! declaration->declarator_list->next) + return false; + + return true; + } + + virtual int match(const QList<AST *> &path, QTextCursor tc) + { + setTextCursor(tc); + + CoreDeclaratorAST *core_declarator = 0; + + int index = path.size() - 1; + for (; index != -1; --index) { + AST *node = path.at(index); + + if (CoreDeclaratorAST *coreDecl = node->asCoreDeclarator()) + core_declarator = coreDecl; + + else if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) { + if (checkDeclaration(simpleDecl)) { + declaration = simpleDecl; + + const int cursorPosition = tc.selectionStart(); + + const int startOfDeclSpecifier = startOf(declaration->decl_specifier_list->firstToken()); + const int endOfDeclSpecifier = endOf(declaration->decl_specifier_list->lastToken() - 1); + + if (cursorPosition >= startOfDeclSpecifier && cursorPosition <= endOfDeclSpecifier) + return index; // the AST node under cursor is a specifier. + + if (core_declarator) { + const int startOfCoreDeclarator = startOf(core_declarator); + const int endOfCoreDeclarator = endOf(core_declarator); + + if (cursorPosition >= startOfCoreDeclarator && cursorPosition <= endOfCoreDeclarator) + return index; // got a core-declarator under the text cursor. + } + } + + break; + } + } + + return -1; + } + + virtual void apply() + { + QTextCursor completeDeclaration = createCursor(declaration); + + SpecifierListAST *specifiers = declaration->decl_specifier_list; + const QString declSpecifiers = textOf(startOf(specifiers->firstToken()), endOf(specifiers->lastToken() - 1)); + + DeclaratorAST *declarator = declaration->declarator_list->value; + replace(endOf(declarator), startOf(declaration->semicolon_token), QString()); + + QString text; + for (DeclaratorListAST *it = declaration->declarator_list->next; it; it = it->next) { + DeclaratorAST *declarator = it->value; + + text += QLatin1Char('\n'); + text += declSpecifiers; + text += QLatin1Char(' '); + text += textOf(declarator); + text += QLatin1String(";"); + } + + insert(endOf(declaration->semicolon_token), text); + + completeDeclaration.beginEditBlock(); + execute(); + editor->indentInsertedText(completeDeclaration); + completeDeclaration.endEditBlock(); + } + +private: + SimpleDeclarationAST *declaration; + CPPEditor *editor; +}; + class TakeDeclarationOp: public QuickFixOperation { public: @@ -205,14 +316,7 @@ public: virtual void apply() { - QTextCursor completeIfStatement = selectNode(pattern); - { - // ### HACK - const int anchor = completeIfStatement.anchor(); - const int position = completeIfStatement.position(); - completeIfStatement.setPosition(position); - completeIfStatement.setPosition(anchor, QTextCursor::KeepAnchor); - } + QTextCursor completeIfStatement = createCursor(pattern); QString name = selectNode(core).selectedText(); QString declaration = selectNode(condition).selectedText(); @@ -321,14 +425,7 @@ public: void splitAndCondition() { - QTextCursor completeIfStatement = selectNode(pattern); - { - // ### HACK - const int anchor = completeIfStatement.anchor(); - const int position = completeIfStatement.position(); - completeIfStatement.setPosition(position); - completeIfStatement.setPosition(anchor, QTextCursor::KeepAnchor); - } + QTextCursor completeIfStatement = createCursor(pattern); StatementAST *ifTrueStatement = pattern->statement; CompoundStatementAST *compoundStatement = ifTrueStatement->asCompoundStatement(); @@ -371,14 +468,7 @@ public: void splitOrCondition() { - QTextCursor completeIfStatement = selectNode(pattern); - { - // ### HACK - const int anchor = completeIfStatement.anchor(); - const int position = completeIfStatement.position(); - completeIfStatement.setPosition(position); - completeIfStatement.setPosition(anchor, QTextCursor::KeepAnchor); - } + QTextCursor completeIfStatement = createCursor(pattern); StatementAST *ifTrueStatement = pattern->statement; CompoundStatementAST *compoundStatement = ifTrueStatement->asCompoundStatement(); @@ -496,6 +586,17 @@ QTextCursor QuickFixOperation::selectNode(AST *ast) const return tc; } +QTextCursor QuickFixOperation::createCursor(AST *ast) const +{ + QTextCursor cursor = selectNode(ast); + // ### HACK + const int anchor = cursor.anchor(); + const int position = cursor.position(); + cursor.setPosition(position); + cursor.setPosition(anchor, QTextCursor::KeepAnchor); + return cursor; +} + void QuickFixOperation::move(int start, int end, int to) { if (end > start) @@ -533,6 +634,19 @@ void QuickFixOperation::insert(int at, const QString &text) replace(at, at, text); } +QString QuickFixOperation::textOf(int firstOffset, int lastOffset) const +{ + QTextCursor tc = _textCursor; + tc.setPosition(firstOffset); + tc.setPosition(lastOffset, QTextCursor::KeepAnchor); + return tc.selectedText(); +} + +QString QuickFixOperation::textOf(AST *ast) const +{ + return selectNode(ast).selectedText(); +} + void QuickFixOperation::execute() { _textWriter.write(&_textCursor); @@ -573,13 +687,15 @@ int CPPQuickFixCollector::startCompletion(TextEditor::ITextEditable *editable) // ### build the list of the quick fix ops by scanning path. QSharedPointer<RewriteLogicalAndOp> rewriteLogicalAndOp(new RewriteLogicalAndOp(info.doc, info.snapshot)); - QSharedPointer<SplitIfStatementOp> splitIfStatement(new SplitIfStatementOp(info.doc, info.snapshot, _editor)); - QSharedPointer<TakeDeclarationOp> takeDeclaration(new TakeDeclarationOp(info.doc, info.snapshot, _editor)); + QSharedPointer<SplitIfStatementOp> splitIfStatementOp(new SplitIfStatementOp(info.doc, info.snapshot, _editor)); + QSharedPointer<TakeDeclarationOp> takeDeclarationOp(new TakeDeclarationOp(info.doc, info.snapshot, _editor)); + QSharedPointer<SplitSimpleDeclarationOp> splitSimpleDeclarationOp(new SplitSimpleDeclarationOp(info.doc, info.snapshot, _editor)); QList<QuickFixOperationPtr> candidates; candidates.append(rewriteLogicalAndOp); - candidates.append(splitIfStatement); - candidates.append(takeDeclaration); + candidates.append(splitIfStatementOp); + candidates.append(takeDeclarationOp); + candidates.append(splitSimpleDeclarationOp); QMultiMap<int, QuickFixOperationPtr> matchedOps; diff --git a/src/plugins/cppeditor/cppquickfix.h b/src/plugins/cppeditor/cppquickfix.h index d5d9dfda8da33ad5c5efa2c43de25cd8cd7ac2c6..87e5d49195ee2b7e2b538ee527a257cf3b18ba13 100644 --- a/src/plugins/cppeditor/cppquickfix.h +++ b/src/plugins/cppeditor/cppquickfix.h @@ -91,6 +91,11 @@ protected: void replace(const CPlusPlus::AST *ast, const QString &replacement); void insert(int at, const QString &text); + QString textOf(int firstOffset, int lastOffset) const; + QString textOf(CPlusPlus::AST *ast) const; + + QTextCursor createCursor(CPlusPlus::AST *ast) const; // ### rename me + void execute(); private: