From 0bac3ad279450d6a19093e0d58036774cc66c7ca Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 24 May 2019 15:09:00 +0200 Subject: [PATCH] C++: Do not auto-insert '}' after control flow constructs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...as this rather gets in the way. As before, pressing ENTER after { will still auto insert } on the next line. Fixes: QTCREATORBUG-18872 Change-Id: I8ee082962b5ee82781e51c3e5ee146343f808332 Reviewed-by: David Schulz Reviewed-by: André Hartmann --- src/libs/cplusplus/MatchingText.cpp | 29 +++++++++++++++++++ tests/unit/unittest/matchingtext-test.cpp | 35 +++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp index c22d3fe89cf..59440813a70 100644 --- a/src/libs/cplusplus/MatchingText.cpp +++ b/src/libs/cplusplus/MatchingText.cpp @@ -358,6 +358,32 @@ static bool isAfterRecordLikeDefinition(const BackwardsScanner &tokens, int inde return false; } +static bool isControlFlowKeywordRequiringParentheses(const Token &token) +{ + return token.is(T_IF) + || token.is(T_WHILE) + || token.is(T_FOR) + || token.is(T_SWITCH) + || token.is(T_CATCH); +} + +static bool isAfterControlFlow(const BackwardsScanner &tokens, int index) +{ + const Token &token = tokens[index]; + if (token.is(T_DO) || token.is(T_ELSE) || token.is(T_TRY)) + return true; + + if (token.is(T_RPAREN)) { + const int startIndex = index + 1; + const int matchingBraceIndex = tokens.startOfMatchingBrace(startIndex); + if (matchingBraceIndex == startIndex) + return false; // No matching paren found. + return isControlFlowKeywordRequiringParentheses(tokens[matchingBraceIndex - 1]); + } + + return false; +} + static bool allowAutoClosingBrace(const QTextCursor &cursor, MatchingText::IsNextBlockDeeperIndented isNextIndented) { @@ -370,6 +396,9 @@ static bool allowAutoClosingBrace(const QTextCursor &cursor, if (tokens[index].isStringLiteral()) return false; + if (isAfterControlFlow(tokens, index)) + return false; + if (isAfterNamespaceDefinition(tokens, index)) return false; diff --git a/tests/unit/unittest/matchingtext-test.cpp b/tests/unit/unittest/matchingtext-test.cpp index 081e356764e..b49731d3e62 100644 --- a/tests/unit/unittest/matchingtext-test.cpp +++ b/tests/unit/unittest/matchingtext-test.cpp @@ -221,6 +221,41 @@ TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotInTheMiddle) ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); } +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotAfterControlFlow_WhileAndFriends) +{ + const Document document("while (true) @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotAfterControlFlow_DoAndFriends) +{ + const Document document("do @"); + + ASSERT_FALSE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_InvalidCode_UnbalancedParens) +{ + const Document document(") @"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_InvalidCode_UnbalancedParens2) +{ + const Document document("while true) @"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + +TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_InvalidCode_OnlyBalancedParens) +{ + const Document document("() @"); + + ASSERT_TRUE(MT::contextAllowsAutoParentheses(document.cursor, "{")); +} + TEST_F(MatchingText, ContextAllowsAutoParentheses_CurlyBrace_NotBeforeNamedNamespace) { const Document document("namespace X @");