diff --git a/src/libs/cplusplus/BackwardsScanner.cpp b/src/libs/cplusplus/BackwardsScanner.cpp index df2916a6d757f1249a9ba61f2431f90ff5fedd32..251fa9bd19e1f51010857c10db0fea9fdcc06375 100644 --- a/src/libs/cplusplus/BackwardsScanner.cpp +++ b/src/libs/cplusplus/BackwardsScanner.cpp @@ -27,6 +27,7 @@ ** **************************************************************************/ #include "BackwardsScanner.h" +#include <Token.h> #include <QtGui/QTextCursor> using namespace CPlusPlus; @@ -42,10 +43,16 @@ BackwardsScanner::BackwardsScanner(const QTextCursor &cursor, int maxBlockCount) _tokens.append(_tokenize(_text, previousBlockState(_block))); } -QList<SimpleToken> BackwardsScanner::tokens() const +int BackwardsScanner::state() const +{ return _tokenize.state(); } + +const QList<SimpleToken> &BackwardsScanner::tokens() const { return _tokens; } -const SimpleToken &BackwardsScanner::operator[](int i) +const SimpleToken &BackwardsScanner::operator[](int i) const +{ return const_cast<BackwardsScanner *>(this)->fetchToken(i); } + +const SimpleToken &BackwardsScanner::fetchToken(int i) { while (_offset + i < 0) { _block = _block.previous(); @@ -77,10 +84,13 @@ const SimpleToken &BackwardsScanner::operator[](int i) return _tokens.at(_offset + i); } +int BackwardsScanner::startToken() const +{ return _tokens.size(); } + int BackwardsScanner::startPosition() const { return _block.position(); } -const QString &BackwardsScanner::text() const +QString BackwardsScanner::text() const { return _text; } QString BackwardsScanner::text(int begin, int end) const @@ -90,7 +100,14 @@ QString BackwardsScanner::text(int begin, int end) const return _text.mid(firstToken.begin(), lastToken.end() - firstToken.begin()); } -int BackwardsScanner::previousBlockState(const QTextBlock &block) +QStringRef BackwardsScanner::textRef(int begin, int end) const +{ + const SimpleToken &firstToken = _tokens.at(begin + _offset); + const SimpleToken &lastToken = _tokens.at(end + _offset - 1); + return _text.midRef(firstToken.begin(), lastToken.end() - firstToken.begin()); +} + +int BackwardsScanner::previousBlockState(const QTextBlock &block) const { const QTextBlock prevBlock = block.previous(); @@ -103,3 +120,45 @@ int BackwardsScanner::previousBlockState(const QTextBlock &block) return 0; } + +int BackwardsScanner::startOfMatchingBrace(int index) const +{ + const BackwardsScanner &tk = *this; + + if (tk[index - 1].is(T_RPAREN)) { + int i = index - 1; + int count = 0; + do { + if (tk[i].is(T_LPAREN)) { + if (! ++count) + return i; + } else if (tk[i].is(T_RPAREN)) + --count; + --i; + } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); + } else if (tk[index - 1].is(T_RBRACKET)) { + int i = index - 1; + int count = 0; + do { + if (tk[i].is(T_LBRACKET)) { + if (! ++count) + return i; + } else if (tk[i].is(T_RBRACKET)) + --count; + --i; + } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); + } else if (tk[index - 1].is(T_GREATER)) { + int i = index - 1; + int count = 0; + do { + if (tk[i].is(T_LESS)) { + if (! ++count) + return i; + } else if (tk[i].is(T_GREATER)) + --count; + --i; + } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); + } + + return index; +} diff --git a/src/libs/cplusplus/BackwardsScanner.h b/src/libs/cplusplus/BackwardsScanner.h index c38060040bc3e62d9047bebde8b8d0b321f28913..925527cbcf1b39793b4c2377cdc3d3f178f492ce 100644 --- a/src/libs/cplusplus/BackwardsScanner.h +++ b/src/libs/cplusplus/BackwardsScanner.h @@ -43,13 +43,23 @@ class CPLUSPLUS_EXPORT BackwardsScanner public: BackwardsScanner(const QTextCursor &cursor, int maxBlockCount = MAX_BLOCK_COUNT); - QList<SimpleToken> tokens() const; + int state() const; + int startToken() const; + int startPosition() const; - const QString &text() const; - const SimpleToken &operator[](int i); + QString text() const; QString text(int begin, int end) const; - int previousBlockState(const QTextBlock &block); + QStringRef textRef(int begin, int end) const; + + const SimpleToken &operator[](int i) const; + + int startOfMatchingBrace(int index) const; + int previousBlockState(const QTextBlock &block) const; + +private: + const SimpleToken &fetchToken(int i); + const QList<SimpleToken> &tokens() const; private: QList<SimpleToken> _tokens; diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index 1cc546de2265068f5919ab932468e2699eeacb5f..622b420048b6b845fddf8c2f575b6babca341444 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -43,46 +43,6 @@ ExpressionUnderCursor::ExpressionUnderCursor() ExpressionUnderCursor::~ExpressionUnderCursor() { } -int ExpressionUnderCursor::startOfMatchingBrace(BackwardsScanner &tk, int index) -{ - if (tk[index - 1].is(T_RPAREN)) { - int i = index - 1; - int count = 0; - do { - if (tk[i].is(T_LPAREN)) { - if (! ++count) - return i; - } else if (tk[i].is(T_RPAREN)) - --count; - --i; - } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); - } else if (tk[index - 1].is(T_RBRACKET)) { - int i = index - 1; - int count = 0; - do { - if (tk[i].is(T_LBRACKET)) { - if (! ++count) - return i; - } else if (tk[i].is(T_RBRACKET)) - --count; - --i; - } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); - } else if (tk[index - 1].is(T_GREATER)) { - int i = index - 1; - int count = 0; - do { - if (tk[i].is(T_LESS)) { - if (! ++count) - return i; - } else if (tk[i].is(T_GREATER)) - --count; - --i; - } while (count != 0 && tk[i].isNot(T_EOF_SYMBOL)); - } - - return index; -} - int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index) { // tk is a reference to a const QList. So, don't worry about [] access. @@ -122,10 +82,10 @@ int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index) } return index - 1; } else if (tk[index - 1].is(T_RPAREN)) { - int rparenIndex = startOfMatchingBrace(tk, index); + int rparenIndex = tk.startOfMatchingBrace(index); if (rparenIndex != index) { if (tk[rparenIndex - 1].is(T_GREATER)) { - int lessIndex = startOfMatchingBrace(tk, rparenIndex); + int lessIndex = tk.startOfMatchingBrace(rparenIndex); if (lessIndex != rparenIndex - 1) { if (tk[lessIndex - 1].is(T_DYNAMIC_CAST) || tk[lessIndex - 1].is(T_STATIC_CAST) || @@ -144,13 +104,13 @@ int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index) } return index; } else if (tk[index - 1].is(T_RBRACKET)) { - int rbracketIndex = startOfMatchingBrace(tk, index); + int rbracketIndex = tk.startOfMatchingBrace(index); if (rbracketIndex != index) return startOfExpression(tk, rbracketIndex); return index; } else if (tk[index - 1].is(T_COLON_COLON)) { if (tk[index - 2].is(T_GREATER)) { // ### not exactly - int lessIndex = startOfMatchingBrace(tk, index - 1); + int lessIndex = tk.startOfMatchingBrace(index - 1); if (lessIndex != index - 1) return startOfExpression(tk, lessIndex); return index - 1; @@ -185,7 +145,7 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) _jumpedComma = false; - const int initialSize = scanner.tokens().size(); + const int initialSize = scanner.startToken(); const int i = startOfExpression(scanner, initialSize); if (i == initialSize) return QString(); @@ -199,7 +159,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) BackwardsScanner scanner(cursor); - int index = scanner.tokens().size(); + int index = scanner.startToken(); forever { const SimpleToken &tk = scanner[index - 1]; @@ -209,7 +169,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) else if (tk.is(T_LPAREN)) return scanner.startPosition() + tk.position(); else if (tk.is(T_RPAREN)) { - int matchingBrace = startOfMatchingBrace(scanner, index); + int matchingBrace = scanner.startOfMatchingBrace(index); if (matchingBrace == index) // If no matching brace found return -1; diff --git a/src/libs/cplusplus/ExpressionUnderCursor.h b/src/libs/cplusplus/ExpressionUnderCursor.h index 50404d2d5d13b5242adc27714944644add269a3c..2c5ca12bcb6ae612146f0195e5d9ce73953af88a 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.h +++ b/src/libs/cplusplus/ExpressionUnderCursor.h @@ -54,7 +54,6 @@ public: int startOfFunctionCall(const QTextCursor &cursor); private: - int startOfMatchingBrace(BackwardsScanner &tk, int index); int startOfExpression(BackwardsScanner &tk, int index); int previousBlockState(const QTextBlock &block); bool isAccessToken(const SimpleToken &tk); diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14449584d140db21803c82b60a50c12d38645bb8 --- /dev/null +++ b/src/libs/cplusplus/MatchingText.cpp @@ -0,0 +1,131 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ +#include "MatchingText.h" +#include "BackwardsScanner.h" + +#include <Token.h> +#include <QtDebug> + +using namespace CPlusPlus; + +MatchingText::MatchingText() +{ } + +QString MatchingText::insertParagraphSeparator(const QTextCursor &tc) const +{ + BackwardsScanner tk(tc, 400); + int index = tk.startToken(); + + if (tk[index - 1].isNot(T_LBRACE)) + return QString(); // nothing to do. + + --index; // consume the `{' + + const SimpleToken &token = tk[index - 1]; + + if (token.is(T_STRING_LITERAL) && tk[index - 2].is(T_EXTERN)) { + // recognized extern "C" + return QLatin1String("}"); + + } else if (token.is(T_IDENTIFIER)) { + int i = index - 1; + + forever { + const SimpleToken ¤t = tk[i - 1]; + + if (current.is(T_EOF_SYMBOL)) + break; + + else if (current.is(T_CLASS) || current.is(T_STRUCT) || current.is(T_UNION)) + return QLatin1String("};"); // found a class key. + + else if (current.is(T_NAMESPACE)) + return QLatin1String("}"); // found a namespace declaration + + else if (current.is(T_SEMICOLON)) + break; // found the `;' sync token + + else if (current.is(T_LBRACE) || current.is(T_RBRACE)) + break; // braces are considered sync tokens + + else if (current.is(T_LPAREN) || current.is(T_RPAREN)) + break; // sync token + + else if (current.is(T_LBRACKET) || current.is(T_RBRACKET)) + break; // sync token + + --i; + } + } + + if (token.is(T_NAMESPACE)) { + // anonymous namespace + return QLatin1String("}"); + + } else if (token.is(T_CLASS) || token.is(T_STRUCT) || token.is(T_UNION)) { + if (tk[index - 2].is(T_TYPEDEF)) { + // recognized: + // typedef struct { + // + // in this case we don't want to insert the extra semicolon+newline. + return QLatin1String("}"); + } + + // anonymous class + return QLatin1String("};"); + + } else if (token.is(T_RPAREN)) { + // search the matching brace. + const int lparenIndex = tk.startOfMatchingBrace(index); + + if (lparenIndex == index) { + // found an unmatched brace. We don't really know to do in this case. + return QString(); + } + + // look at the token before the matched brace + const SimpleToken &tokenBeforeBrace = tk[lparenIndex - 1]; + + if (tokenBeforeBrace.is(T_IF)) { + // recognized an if statement + return QLatin1String("}"); + + } else if (tokenBeforeBrace.is(T_FOR) || tokenBeforeBrace.is(T_WHILE)) { + // recognized a for-like statement + return QLatin1String("}"); + + } + + // if we reached this point there is a good chance that we are parsing a function definition + return QLatin1String("}"); + } + + // match the block + return QLatin1String("}"); +} diff --git a/src/libs/cplusplus/MatchingText.h b/src/libs/cplusplus/MatchingText.h new file mode 100644 index 0000000000000000000000000000000000000000..3f7ef2cebf97c3481315cd576992c27950e7437c --- /dev/null +++ b/src/libs/cplusplus/MatchingText.h @@ -0,0 +1,49 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ +#ifndef MATCHINGTEXT_H +#define MATCHINGTEXT_H + +#include <CPlusPlusForwardDeclarations.h> +#include <QtGui/QTextCursor> + +namespace CPlusPlus { + +class BackwardsScanner; + +class CPLUSPLUS_EXPORT MatchingText +{ +public: + MatchingText(); + + QString insertParagraphSeparator(const QTextCursor &tc) const; +}; + +} // end of namespace CPlusPlus + +#endif // MATCHINGTEXT_H diff --git a/src/libs/cplusplus/cplusplus-lib.pri b/src/libs/cplusplus/cplusplus-lib.pri index 1cc2bd08e10666da9451b4efa2a723194a02fce5..34caa520a80b538ac0af4d7eb9ad637cf9b23899 100644 --- a/src/libs/cplusplus/cplusplus-lib.pri +++ b/src/libs/cplusplus/cplusplus-lib.pri @@ -9,6 +9,7 @@ HEADERS += \ $$PWD/ExpressionUnderCursor.h \ $$PWD/TokenUnderCursor.h \ $$PWD/BackwardsScanner.h \ + $$PWD/MatchingText.h \ $$PWD/OverviewModel.h SOURCES += \ @@ -16,6 +17,7 @@ SOURCES += \ $$PWD/ExpressionUnderCursor.cpp \ $$PWD/TokenUnderCursor.cpp \ $$PWD/BackwardsScanner.cpp \ + $$PWD/MatchingText.cpp \ $$PWD/OverviewModel.cpp } diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index a90c2fbfad4926d08d5a5c75bbad2d3bade2f20c..ee8f965497d9cc78321eaee44e914273f33411c3 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -52,6 +52,7 @@ #include <cplusplus/SimpleLexer.h> #include <cplusplus/TokenUnderCursor.h> #include <cplusplus/TypeOfExpression.h> +#include <cplusplus/MatchingText.h> #include <cpptools/cppmodelmanagerinterface.h> #include <coreplugin/icore.h> @@ -1374,7 +1375,11 @@ int CPPEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor) if (braceDepth > 0) { // we do have an extra brace, let's close it int pos = cursor.position(); - cursor.insertText(QLatin1String("}")); + + MatchingText matchingText; + const QString textToInsert = matchingText.insertParagraphSeparator(cursor); + + cursor.insertText(textToInsert); cursor.setPosition(pos); const TabSettings &ts = tabSettings(); if (ts.m_autoIndent) {