From 752dd880e00a01b08bb3fb389500c55f0cc8ba0d Mon Sep 17 00:00:00 2001 From: Roberto Raggi <roberto.raggi@nokia.com> Date: Fri, 5 Jun 2009 14:30:18 +0200 Subject: [PATCH] Show how to simplify declarations. e.g. static int i, *ptr = &i; will be replaced with static int i; static int *ptr = &i; using the editor's context menu > Simplify Declarations --- src/plugins/cppeditor/cppeditor.cpp | 126 ++++++++++++++++++++++++++++ src/plugins/cppeditor/cppeditor.h | 3 + 2 files changed, 129 insertions(+) diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 29b7f6cd11c..59aa1b863ce 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -143,6 +143,111 @@ protected: } }; +class SimplifyDeclarations: protected ASTVisitor +{ + CPPEditor *_editor; + Document::Ptr _doc; + QByteArray _source; + QTextCursor _textCursor; + unsigned _line; + unsigned _column; + +public: + SimplifyDeclarations(CPPEditor *ed, Document::Ptr doc) + : ASTVisitor(doc->control()), _editor(ed), + _doc(doc), _source(doc->source()) + { } + + void operator()(QTextCursor tc) + { + _textCursor = tc; + + _line = _textCursor.blockNumber() + 1; + _column = _textCursor.columnNumber() + 1; + + accept(_doc->translationUnit()->ast()); + } + +protected: + QByteArray text(unsigned firstToken, unsigned lastToken) const + { + const unsigned begin = tokenAt(firstToken).begin(); + const unsigned end = tokenAt(lastToken - 1).end(); + return _source.mid(begin, end - begin); + } + + virtual bool visit(SimpleDeclarationAST *ast) + { + if (! ast->decl_specifier_seq) { + // e.g a ctor/dtor or a cast-function-id. + return true; + } if (! ast->declarators) { + // e.g. + // struct foo { int a; }; + return true; + } else if (! ast->declarators->next) { + // e.g. + // int a; + return true; + } + + unsigned startLine, startColumn; + unsigned endLine, endColumn; + + getTokenStartPosition(ast->firstToken(), &startLine, &startColumn); + getTokenEndPosition(ast->lastToken() - 1, &endLine, &endColumn); + + if (_line < startLine || (_line == startLine && _column < startColumn)) + return true; + else if (_line > endLine || (_line == endLine && _column >= endColumn)) + return true; + + unsigned beginOfDeclSpecifiers = ast->decl_specifier_seq->firstToken(); + unsigned endOfDeclSpecifiers = 0; + + for (SpecifierAST *spec = ast->decl_specifier_seq; spec; spec = spec->next) { + if (spec->asClassSpecifier() != 0) { + // e.g. + // struct foo { int a; } x, y, z; + return true; + } else if (! spec->next) + endOfDeclSpecifiers = spec->lastToken(); + } + + const QByteArray declSpecifiers = + text(beginOfDeclSpecifiers, endOfDeclSpecifiers); + + QByteArray code; + for (DeclaratorListAST *it = ast->declarators; it; it = it->next) { + DeclaratorAST *decl = it->declarator; + + const QByteArray declaratorText = text(decl->firstToken(), decl->lastToken()); + code += declSpecifiers; + code += ' '; + code += declaratorText; + code += ';'; + code += '\n'; + } + + const QString refactoredCode = QString::fromUtf8(code); + + QTextCursor tc = _textCursor; + tc.beginEditBlock(); + tc.setPosition(tc.document()->findBlockByNumber(startLine - 1).position() + startColumn - 1); + int startPos = tc.position(); + tc.setPosition(tc.document()->findBlockByNumber(endLine - 1).position() + endColumn - 1, + QTextCursor::KeepAnchor); + tc.removeSelectedText(); + tc.insertText(refactoredCode); + tc.setPosition(startPos); + tc.setPosition(tc.position() + refactoredCode.length(), QTextCursor::KeepAnchor); + _editor->indentInsertedText(tc); + tc.endEditBlock(); + + return true; + } +}; + } // end of anonymous namespace static QualifiedNameId *qualifiedNameIdForSymbol(Symbol *s, const LookupContext &context) @@ -411,6 +516,18 @@ void CPPEditor::reformatDocument() c.insertText(QString::fromUtf8(str.c_str(), str.length())); } +void CPPEditor::simplifyDeclarations() +{ + Snapshot snapshot = m_modelManager->snapshot(); + const QByteArray plainText = toPlainText().toUtf8(); + const QString fileName = file()->fileName(); + const QByteArray preprocessedCode = snapshot.preprocessedCode(plainText, fileName); + Document::Ptr doc = snapshot.documentFromSource(preprocessedCode, fileName); + + SimplifyDeclarations simplify(this, doc); + simplify(textCursor()); +} + void CPPEditor::updateFileName() { } @@ -848,6 +965,11 @@ bool CPPEditor::isElectricCharacter(const QChar &ch) const return false; } +void CPPEditor::indentInsertedText(const QTextCursor &tc) +{ + indent(tc.document(), tc, QChar::Null); +} + // Indent a code line based on previous template <class Iterator> static void indentCPPBlock(const CPPEditor::TabSettings &ts, @@ -890,6 +1012,10 @@ void CPPEditor::contextMenuEvent(QContextMenuEvent *e) foreach (QAction *action, contextMenu->actions()) menu->addAction(action); + QAction *simplifyDeclarations = new QAction(tr("Simplify Declarations"), menu); + connect(simplifyDeclarations, SIGNAL(triggered()), this, SLOT(simplifyDeclarations())); + menu->addAction(simplifyDeclarations); + menu->exec(e->globalPos()); delete menu; } diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index e8dd9b416d4..fb3fa2f8227 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -87,6 +87,8 @@ public: void unCommentSelection(); + void indentInsertedText(const QTextCursor &tc); + public slots: virtual void setFontSettings(const TextEditor::FontSettings &); virtual void setDisplaySettings(const TextEditor::DisplaySettings &); @@ -119,6 +121,7 @@ private slots: void updateMethodBoxToolTip(); void onDocumentUpdated(CPlusPlus::Document::Ptr doc); void reformatDocument(); + void simplifyDeclarations(); private: bool sortedMethodOverview() const; -- GitLab