diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp index c0847bc5951..d4b3566ad90 100644 --- a/src/libs/cplusplus/MatchingText.cpp +++ b/src/libs/cplusplus/MatchingText.cpp @@ -120,6 +120,7 @@ QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QStri QString text = textToProcess; const QString blockText = tc.block().text().mid(tc.positionInBlock()); + const QString trimmedBlockText = blockText.trimmed(); const int length = qMin(blockText.length(), textToProcess.length()); const QChar previousChar = doc->characterAt(tc.selectionEnd() - 1); @@ -190,10 +191,14 @@ QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QStri QString result; foreach (const QChar &ch, text) { - if (ch == QLatin1Char('(')) result += ')'; - else if (ch == QLatin1Char('[')) result += ']'; - else if (ch == QLatin1Char('"')) result += '"'; - else if (ch == QLatin1Char('\'')) result += '\''; + if (ch == QLatin1Char('(')) result += QLatin1Char(')'); + else if (ch == QLatin1Char('[')) result += QLatin1Char(']'); + else if (ch == QLatin1Char('"')) result += QLatin1Char('"'); + else if (ch == QLatin1Char('\'')) result += QLatin1Char('\''); + // Handle '{' appearance within functinon call context + else if (ch == QLatin1Char('{') && !trimmedBlockText.isEmpty() && trimmedBlockText.at(0) == QLatin1Char(')')) + result += QLatin1Char('}'); + } return result; diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp index 50f21656598..be10cab616c 100644 --- a/src/plugins/cpptools/cppcodeformatter.cpp +++ b/src/plugins/cpptools/cppcodeformatter.cpp @@ -229,9 +229,74 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) default: tryExpression(); break; } break; + case lambda_instroducer_or_subscribtion: + switch (kind) { + case T_RBRACKET: turnInto(lambda_declarator_expected); break; // we can't determine exact kind of expression. Try again + case T_COMMA: + case T_EQUAL: turnInto(lambda_instroducer); break; // ',' or '=' inside brackets can be only whithin lambda capture list + case T_IDENTIFIER: // '&', id, 'this' are allowed both in the capture list and subscribtion + case T_AMPER: + case T_THIS: break; + default: leave(); leave(); tryExpression(m_currentState.at(m_currentState.size() - 1).type == declaration_start); break; + // any other symbol allowed only in subscribtion operator + } break; + + case lambda_declarator_expected: + switch (kind) { + case T_LPAREN: turnInto(lambda_declarator_or_expression); break; // '(' just after ']'. We can't make decisioin here + case T_LBRACE: turnInto(substatement_open); break; // '{' just after ']' opens a lambda-compound statement + default: + if (m_currentState.size() >= 3 && m_currentState.at(m_currentState.size() - 3).type == declaration_start) + leave(); + + leave(); + continue; + } break; + + case lambda_instroducer: + switch (kind) { + case T_RBRACKET: turnInto(lambda_declarator); break; + } break; + + case lambda_declarator_or_expression: + switch (kind) { + case T_LBRACE: turnInto(substatement_open); /*tryStatement();*/ break; + case T_RPAREN: turnInto(lambda_statement_expected); break; + case T_IDENTIFIER: + case T_SEMICOLON: leave(); continue; + default: + if (tryDeclaration()) {// We found the declaration within '()' so it is lambda declarator + leave(); + turnInto(lambda_declarator); + break; + } else { + turnInto(expression); + enter(arglist_open); + continue; + } + } break; + + case lambda_statement_expected: + switch (kind) { + case T_LBRACE: turnInto(substatement_open); /*tryStatement()*/; break; + case T_NOEXCEPT: // 'noexcept', 'decltype' and 'mutable' are only part of lambda declarator + case T_DECLTYPE: + case T_MUTABLE: turnInto(lambda_declarator); break; + case T_RBRACKET: // '[', ']' and '->' can be part of lambda declarator + case T_LBRACKET: + case T_ARROW: break; + default: leave(); continue; + } break; + + case lambda_declarator: + switch (kind) { + case T_LBRACE: turnInto(substatement_open); /*tryStatement()*/; break; + } break; + case arglist_open: switch (kind) { case T_SEMICOLON: leave(true); break; + case T_LBRACE: enter(brace_list_open); break; case T_RBRACE: leave(true); continue; case T_RPAREN: leave(); break; default: tryExpression(); break; @@ -739,6 +804,9 @@ bool CodeFormatter::tryExpression(bool alsoExpression) } } break; + case T_LBRACKET: + newState = lambda_instroducer_or_subscribtion; + break; } if (newState != -1) { diff --git a/src/plugins/cpptools/cppcodeformatter.h b/src/plugins/cpptools/cppcodeformatter.h index 8dab0dbc81e..a7da67f57c7 100644 --- a/src/plugins/cpptools/cppcodeformatter.h +++ b/src/plugins/cpptools/cppcodeformatter.h @@ -177,7 +177,16 @@ public: // must be public to make Q_GADGET introspection work assign_open, // after an assignment token expression, // after a '=' in a declaration_start once we're sure it's not '= {' - assign_open_or_initializer // after a '=' in a declaration start + assign_open_or_initializer, // after a '=' in a declaration start + + lambda_instroducer_or_subscribtion, // just after '[' or in cases '[]' and '[id]' when we're not sure in the exact kind of expression + lambda_declarator_expected, // just after ']' in lambda_introducer_or_subscribtion + lambda_declarator_or_expression, // just after '](' when previous state is 'lambda_instroducer_or_subscribtion' + lambda_statement_expected, + lambda_instroducer, // when '=', '&' or ',' occurred within '[]' + lambda_declarator, // just after ']' when previous state is lambda_introducer + lambda_statement // just after '{' when previous state is lambda_declarator or lambda_declarator_or_expression + }; Q_ENUMS(StateType) diff --git a/src/plugins/texteditor/autocompleter.cpp b/src/plugins/texteditor/autocompleter.cpp index 221531a9b91..166ee33ea68 100644 --- a/src/plugins/texteditor/autocompleter.cpp +++ b/src/plugins/texteditor/autocompleter.cpp @@ -276,10 +276,12 @@ int AutoCompleter::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor, return 0; // verify that we indeed do have an extra opening brace in the document + QTextBlock block = cursor.block(); + const QString textFromCusror = block.text().mid(cursor.positionInBlock()).trimmed(); int braceDepth = BaseTextDocumentLayout::braceDepth(doc->lastBlock()); - if (braceDepth <= 0) - return 0; // braces are all balanced or worse, no need to do anything + if (braceDepth <= 0 && (textFromCusror.isEmpty() || textFromCusror.at(0) != QLatin1Char('}'))) + return 0; // braces are all balanced or worse, no need to do anything and separator inserted not between '{' and '}' // we have an extra brace , let's see if we should close it @@ -289,7 +291,6 @@ int AutoCompleter::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor, if (condition) {| statement; */ - QTextBlock block = cursor.block(); int indentation = tabSettings.indentationColumn(block.text()); if (block.next().isValid()) { // not the last block