diff options
| author | Christian Kandeler <christian.kandeler@qt.io> | 2021-08-30 10:58:08 +0200 |
|---|---|---|
| committer | Christian Kandeler <christian.kandeler@qt.io> | 2021-09-01 14:53:58 +0000 |
| commit | 284817fae6514701902ccdb834c2faa46462f2e8 (patch) | |
| tree | 44a8c7d9813dc110b61c4639036366c7696bd7e9 /src/plugins/cppeditor/cppcodeformatter.cpp | |
| parent | 3e1fa0f170d523971d2c3c12da15a6e291f56511 (diff) | |
| download | qt-creator-284817fae6514701902ccdb834c2faa46462f2e8.tar.gz | |
Merge CppTools into CppEditor
There was no proper separation of responsibilities between these
plugins. In particular, CppTools had lots of editor-related
functionality, so it's not clear why it was separated out in the first
place.
In fact, for a lot of code, it seemed quite arbitrary where it was put
(just one example: switchHeaderSource() was in CppTools, wheras
switchDeclarationDefinition() was in CppEditor).
Merging the plugins will enable us to get rid of various convoluted
pseudo-abstractions that were only introduced to keep up the artificial
separation.
Change-Id: Iafc3bce625b4794f6d4aa03df6cddc7f2d26716a
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/cppeditor/cppcodeformatter.cpp')
| -rw-r--r-- | src/plugins/cppeditor/cppcodeformatter.cpp | 1709 |
1 files changed, 1709 insertions, 0 deletions
diff --git a/src/plugins/cppeditor/cppcodeformatter.cpp b/src/plugins/cppeditor/cppcodeformatter.cpp new file mode 100644 index 0000000000..5ff7aa7f86 --- /dev/null +++ b/src/plugins/cppeditor/cppcodeformatter.cpp @@ -0,0 +1,1709 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "cppcodeformatter.h" + +#include <texteditor/textdocumentlayout.h> +#include <cplusplus/Lexer.h> + +#include <utils/qtcassert.h> + +#include <QDebug> +#include <QMetaEnum> +#include <QTextDocument> +#include <QTextBlock> + +using namespace CPlusPlus; +using namespace TextEditor; + +namespace CppEditor { + +CodeFormatter::~CodeFormatter() = default; + +void CodeFormatter::setTabSize(int tabSize) +{ + m_tabSize = tabSize; +} + +void CodeFormatter::recalculateStateAfter(const QTextBlock &block) +{ + restoreCurrentState(block.previous()); + + bool endedJoined = false; + // Discard newline expected bit from state + const int lexerState = tokenizeBlock(block, &endedJoined) & ~0x80; + m_tokenIndex = 0; + m_newStates.clear(); + + if (tokenAt(0).kind() == T_POUND) { + enter(cpp_macro_start); + m_tokenIndex = 1; + } + + while (m_tokenIndex < m_tokens.size()) { + m_currentToken = tokenAt(m_tokenIndex); + const int kind = m_currentToken.kind(); + + switch (m_currentState.top().type) { + case topmost_intro: + tryDeclaration(); + break; + + case namespace_start: + switch (kind) { + case T_LBRACE: enter(namespace_open); break; + case T_SEMICOLON: + case T_RBRACE: leave(); break; + } break; + + case namespace_open: + if (tryDeclaration()) + break; + switch (kind) { + case T_RBRACE: leave(); continue; // always nested in namespace_start + } break; + + case extern_start: + switch (kind) { + case T_STRING_LITERAL: break; // continue looking for the lbrace + case T_LBRACE: enter(extern_open); break; + default: leave(); continue; + } break; + + case extern_open: + if (tryDeclaration()) + break; + switch (kind) { + case T_RBRACE: leave(); leave(); break; // always nested in extern_start + } break; + + case class_start: + switch (kind) { + case T_SEMICOLON: leave(); break; + case T_LPAREN: turnInto(declaration_start); continue; // "struct Foo bar() {" + case T_LBRACE: enter(class_open); break; + } break; + + case class_open: + if (tryDeclaration()) + break; + switch (kind) { + case T_RBRACE: leave(); continue; // always nested in class_start + } break; + + case access_specifier_start: + switch (kind) { + case T_COLON: leave(); break; + } break; + + case enum_start: + switch (kind) { + case T_SEMICOLON: leave(); break; + case T_LPAREN: turnInto(declaration_start); continue; // "enum Foo bar() {" + case T_LBRACE: enter(enum_open); break; + } break; + + case enum_open: + switch (kind) { + case T_RBRACE: leave(); continue; // always nested in enum_start + case T_LBRACE: enter(brace_list_open); break; + } break; + + case brace_list_open: + switch (kind) { + case T_RBRACE: leave(); break; + case T_LBRACE: enter(brace_list_open); break; + } break; + + case using_start: + switch (kind) { + case T_SEMICOLON: leave(); break; + } break; + + case template_start: + switch (kind) { + case T_LESS: turnInto(template_param); break; + } break; + + case template_param: + switch (kind) { + case T_LESS: enter(template_param); break; + case T_GREATER: leave(); break; + case T_GREATER_GREATER: leave(); leave(); break; // call leave twice to pop both template_param states + } break; + + case operator_declaration: + switch (kind) { + case T_LPAREN: break; + default: leave(); break; + } break; + + case declaration_start: + switch (kind) { + case T_CLASS: + case T_STRUCT: turnInto(class_start); continue; + case T_ENUM: turnInto(enum_start); continue; + case T_RBRACE: leave(true); continue; + case T_SEMICOLON: leave(true); break; + case T_EQUAL: enter(assign_open_or_initializer); break; + case T_LBRACE: enter(defun_open); break; + case T_COLON: enter(member_init_open); enter(member_init_expected); break; + case T_OPERATOR: enter(operator_declaration); break; + case T_GREATER_GREATER: break; + default: tryExpression(true); break; + } break; + + case assign_open_or_initializer: + switch (kind) { + case T_LBRACE: enter(brace_list_open); break; + case T_RBRACE: leave(true); continue; + case T_SEMICOLON: + case T_RPAREN: + case T_COMMA: leave(); continue; + default: enter(assign_open); continue; + } break; + + case expression: + switch (kind) { + case T_RBRACE: leave(true); continue; + case T_SEMICOLON: leave(); continue; + case T_LBRACE: + case T_COLON: + if (m_currentState.at(m_currentState.size() - 2).type == declaration_start) { + // oops, the expression was a function declaration argument list, hand lbrace/colon to declaration_start + leave(); + continue; + } else { + turnInto(substatement_open); + } + break; + case T_ARROW: // Trailing return type? + if (m_currentState.at(m_currentState.size() - 2).type == declaration_start) + leave(); + else + tryExpression(); + break; + default: tryExpression(); break; + } break; + + case assign_open: + switch (kind) { + case T_RBRACE: leave(true); continue; + case T_SEMICOLON: + case T_RPAREN: + case T_COMMA: leave(); continue; + 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 within 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: + if (m_tokenIndex > 0 && tokenAt(m_tokenIndex - 1).kind() == T_ARROW) { + break; + } else { + 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; + } break; + + case braceinit_open: + switch (kind) { + case T_RBRACE: leave(); break; + case T_RPAREN: leave(); continue; // recover? + default: tryExpression(); break; + } break; + + case ternary_op: + switch (kind) { + case T_RPAREN: + case T_COMMA: + case T_SEMICOLON: leave(); continue; // always nested, propagate + default: tryExpression(); break; + } break; + + case stream_op: + case stream_op_cont: + switch (kind) { + case T_LESS_LESS: + case T_GREATER_GREATER: + if (m_currentState.top().type == stream_op) + enter(stream_op_cont); + else // stream_op_cont already + turnInto(stream_op_cont); + break; + case T_RPAREN: + case T_COMMA: + case T_SEMICOLON: leave(); continue; // always nested, propagate + default: tryExpression(); break; + } break; + + case member_init_open: + switch (kind) { + case T_LBRACE: turnInto(defun_open); break; + case T_COMMA: enter(member_init_expected); break; + case T_SEMICOLON: leave(); continue; // try to recover + } break; + + case member_init_expected: + switch (kind) { + case T_IDENTIFIER: turnInto(member_init); break; + case T_LBRACE: + case T_SEMICOLON: leave(); continue; // try to recover + } break; + + case member_init: + switch (kind) { + case T_LBRACE: + case T_LPAREN: enter(member_init_nest_open); break; + case T_RBRACE: + case T_RPAREN: leave(); break; + case T_SEMICOLON: leave(); continue; // try to recover + } break; + + case member_init_nest_open: + switch (kind) { + case T_RBRACE: + case T_RPAREN: leave(); continue; + case T_SEMICOLON: leave(); continue; // try to recover + default: tryExpression(); break; + } break; + + case defun_open: + if (tryStatement()) + break; + switch (kind) { + case T_RBRACE: leave(); leave(); break; // always nested in declaration_start + } break; + + case switch_statement: + case statement_with_condition: + case if_statement: + switch (kind) { + case T_LPAREN: enter(condition_open); break; + default: leave(true); continue; + } break; + + case maybe_else: + if (m_currentToken.isComment()) { + break; + } else if (kind == T_ELSE) { + turnInto(else_clause); + enter(substatement); + break; + } else { + leave(true); + continue; + } + + case else_clause: + // ### shouldn't happen + dump(); + QTC_CHECK(false); + leave(true); + break; + + case do_statement: + // ### shouldn't happen + dump(); + QTC_CHECK(false); + leave(true); + break; + + case return_statement: + switch (kind) { + case T_RBRACE: leave(true); continue; + case T_SEMICOLON: leave(true); break; + } break; + + case substatement: + // prefer substatement_open over block_open + if (kind != T_LBRACE && tryStatement()) + break; + switch (kind) { + case T_LBRACE: turnInto(substatement_open); break; + case T_SEMICOLON: leave(true); break; + case T_RBRACE: leave(true); continue; + } break; + + case for_statement: + switch (kind) { + case T_LPAREN: enter(for_statement_paren_open); break; + default: leave(true); continue; + } break; + + case for_statement_paren_open: + enter(for_statement_init); continue; + + case for_statement_init: + switch (kind) { + case T_SEMICOLON: turnInto(for_statement_condition); break; + case T_LPAREN: enter(condition_paren_open); break; + case T_RPAREN: turnInto(for_statement_expression); continue; + } break; + + case for_statement_condition: + switch (kind) { + case T_SEMICOLON: turnInto(for_statement_expression); break; + case T_LPAREN: enter(condition_paren_open); break; + case T_RPAREN: turnInto(for_statement_expression); continue; + } break; + + case for_statement_expression: + switch (kind) { + case T_RPAREN: leave(); turnInto(substatement); break; + case T_LPAREN: enter(condition_paren_open); break; + } break; + + case case_start: + switch (kind) { + case T_COLON: turnInto(case_cont); break; + } break; + + case case_cont: + if (kind != T_CASE && kind != T_DEFAULT && tryStatement()) + break; + switch (kind) { + case T_RBRACE: + case T_DEFAULT: + case T_CASE: leave(); continue; + } break; + + case substatement_open: + if (tryStatement()) + break; + switch (kind) { + case T_RBRACE: leave(true); break; + } break; + + case condition_open: + switch (kind) { + case T_RPAREN: turnInto(substatement); break; + case T_LPAREN: enter(condition_paren_open); break; + } break; + + case block_open: + if (tryStatement()) + break; + switch (kind) { + case T_RBRACE: leave(true); break; + } break; + + // paren nesting + case condition_paren_open: + switch (kind) { + case T_RPAREN: leave(); break; + case T_LPAREN: enter(condition_paren_open); break; + } break; + + case qt_like_macro: + switch (kind) { + case T_LPAREN: enter(arglist_open); break; + case T_SEMICOLON: leave(true); break; + default: leave(); continue; + } break; + + case label: + switch (kind) { + case T_COLON: leave(); break; + default: leave(); continue; // shouldn't happen + } break; + + case multiline_comment_start: + case multiline_comment_cont: + if (kind != T_COMMENT && kind != T_DOXY_COMMENT) { + leave(); + continue; + } else if (m_tokenIndex == m_tokens.size() - 1 + && lexerState == 0) { + leave(); + } else if (m_tokenIndex == 0 && m_currentToken.isComment()) { + // to allow enter/leave to update the indentDepth + turnInto(multiline_comment_cont); + } + break; + + case cpp_macro_start: { + const int size = m_currentState.size(); + + int previousMarker = -1; + int previousPreviousMarker = -1; + for (int i = size - 1; i >= 0; --i) { + if (m_currentState.at(i).type == cpp_macro_conditional) { + if (previousMarker == -1) { + previousMarker = i; + } else { + previousPreviousMarker = i; + break; + } + } + } + + QStringView tokenText = currentTokenText(); + if (tokenText == QLatin1String("ifdef") + || tokenText == QLatin1String("if") + || tokenText == QLatin1String("ifndef")) { + enter(cpp_macro_conditional); + // copy everything right of previousMarker, excluding cpp_macro_conditional + for (int i = previousMarker + 1; i < size; ++i) + m_currentState += m_currentState.at(i); + } + if (previousMarker != -1) { + if (tokenText == QLatin1String("endif")) { + QStack<State>::iterator begin = m_currentState.begin() + previousPreviousMarker + 1; + QStack<State>::iterator end = m_currentState.begin() + previousMarker + 1; + m_currentState.erase(begin, end); + } else if (tokenText == QLatin1String("else") + || tokenText == QLatin1String("elif")) { + m_currentState.resize(previousMarker + 1); + for (int i = previousPreviousMarker + 1; i < previousMarker; ++i) + m_currentState += m_currentState.at(i); + } + } + + turnInto(cpp_macro); + break; + } + + case cpp_macro: + case cpp_macro_cont: + break; + + case string_open: + case raw_string_open: + if (!m_currentToken.isStringLiteral()) { + leave(); + continue; + } + break; + + default: + qWarning() << "Unhandled state" << m_currentState.top().type; + break; + + } // end of state switch + + ++m_tokenIndex; + } + + int topState = m_currentState.top().type; + + if (topState != multiline_comment_start + && topState != multiline_comment_cont + && (lexerState == T_COMMENT + || lexerState == T_DOXY_COMMENT)) { + enter(multiline_comment_start); + } + + if (topState == qt_like_macro) + leave(true); + + if ((topState == cpp_macro_cont + || topState == cpp_macro) && !endedJoined) + leave(); + + if (topState == cpp_macro && endedJoined) + turnInto(cpp_macro_cont); + + saveCurrentState(block); +} + +void CodeFormatter::indentFor(const QTextBlock &block, int *indent, int *padding) +{ +// qDebug() << "indenting for" << block.blockNumber() + 1; + + restoreCurrentState(block.previous()); + correctIndentation(block); + *indent = m_indentDepth; + *padding = m_paddingDepth; +} + +void CodeFormatter::indentForNewLineAfter(const QTextBlock &block, int *indent, int *padding) +{ + restoreCurrentState(block); + *indent = m_indentDepth; + *padding = m_paddingDepth; + + int lexerState = loadLexerState(block); + m_tokens.clear(); + m_currentLine.clear(); + adjustIndent(m_tokens, lexerState, indent, padding); +} + +void CodeFormatter::updateStateUntil(const QTextBlock &endBlock) +{ + QStack<State> previousState = initialState(); + QTextBlock it = endBlock.document()->firstBlock(); + + // find the first block that needs recalculation + for (; it.isValid() && it != endBlock; it = it.next()) { + BlockData blockData; + if (!loadBlockData(it, &blockData)) + break; + if (blockData.m_blockRevision != it.revision()) + break; + if (previousState.isEmpty() || blockData.m_beginState.isEmpty() + || previousState != blockData.m_beginState) + break; + if (loadLexerState(it) == -1) + break; + previousState = blockData.m_endState; + } + + if (it == endBlock) + return; + + // update everthing until endBlock + for (; it.isValid() && it != endBlock; it = it.next()) { + recalculateStateAfter(it); + } + + // invalidate everything below by marking the state in endBlock as invalid + if (it.isValid()) { + BlockData invalidBlockData; + saveBlockData(&it, invalidBlockData); + } +} + +void CodeFormatter::updateLineStateChange(const QTextBlock &block) +{ + if (!block.isValid()) + return; + + BlockData blockData; + if (loadBlockData(block, &blockData) && blockData.m_blockRevision == block.revision()) + return; + + recalculateStateAfter(block); + + // invalidate everything below by marking the next block's state as invalid + QTextBlock next = block.next(); + if (!next.isValid()) + return; + + saveBlockData(&next, BlockData()); +} + +bool CodeFormatter::isInRawStringLiteral(const QTextBlock &block) const +{ + if (!block.previous().isValid()) + return false; + BlockData blockData; + if (!loadBlockData(block.previous(), &blockData)) + return false; + return !blockData.m_endState.isEmpty() && blockData.m_endState.top().type == raw_string_open; +} + +CodeFormatter::State CodeFormatter::state(int belowTop) const +{ + if (belowTop < m_currentState.size()) + return m_currentState.at(m_currentState.size() - 1 - belowTop); + else + return {}; +} + +int CodeFormatter::tokenIndex() const +{ + return m_tokenIndex; +} + +int CodeFormatter::tokenCount() const +{ + return m_tokens.size(); +} + +const Token &CodeFormatter::currentToken() const +{ + return m_currentToken; +} + +void CodeFormatter::invalidateCache(QTextDocument *document) +{ + if (!document) + return; + + BlockData invalidBlockData; + QTextBlock it = document->firstBlock(); + for (; it.isValid(); it = it.next()) { + saveBlockData(&it, invalidBlockData); + } +} + +void CodeFormatter::enter(int newState) +{ + int savedIndentDepth = m_indentDepth; + int savedPaddingDepth = m_paddingDepth; + onEnter(newState, &m_indentDepth, &savedIndentDepth, &m_paddingDepth, &savedPaddingDepth); + State s(newState, savedIndentDepth, savedPaddingDepth); + m_currentState.push(s); + m_newStates.push(s); +} + +void CodeFormatter::leave(bool statementDone) +{ + QTC_ASSERT(m_currentState.size() > 1, return); + if (m_currentState.top().type == topmost_intro) + return; + + if (m_newStates.size() > 0) + m_newStates.pop(); + + // restore indent depth + State poppedState = m_currentState.pop(); + m_indentDepth = poppedState.savedIndentDepth; + m_paddingDepth = poppedState.savedPaddingDepth; + + int topState = m_currentState.top().type; + + // does it suffice to check if token is T_SEMICOLON or T_RBRACE? + // maybe distinction between leave and turnInto? + if (statementDone) { + if (topState == substatement + || topState == statement_with_condition + || topState == for_statement + || topState == switch_statement + || topState == do_statement) { + leave(true); + } else if (topState == if_statement) { + if (poppedState.type != maybe_else) + enter(maybe_else); + else + leave(true); + } else if (topState == else_clause) { + // leave the else *and* the surrounding if, to prevent another else + leave(); + leave(true); + } + } +} + +void CodeFormatter::correctIndentation(const QTextBlock &block) +{ + const int lexerState = tokenizeBlock(block); + QTC_ASSERT(m_currentState.size() >= 1, return); + + adjustIndent(m_tokens, lexerState, &m_indentDepth, &m_paddingDepth); +} + +bool CodeFormatter::tryExpression(bool alsoExpression) +{ + int newState = -1; + + const int kind = m_currentToken.kind(); + switch (kind) { + case T_LPAREN: newState = arglist_open; break; + case T_QUESTION: newState = ternary_op; break; + case T_LBRACE: newState = braceinit_open; break; + + case T_EQUAL: + case T_AMPER_EQUAL: + case T_CARET_EQUAL: + case T_SLASH_EQUAL: + case T_EXCLAIM_EQUAL: + case T_GREATER_GREATER_EQUAL: + case T_LESS_LESS_EQUAL: + case T_MINUS_EQUAL: + case T_PERCENT_EQUAL: + case T_PIPE_EQUAL: + case T_PLUS_EQUAL: + case T_STAR_EQUAL: + case T_TILDE_EQUAL: + newState = assign_open; + break; + + case T_LESS_LESS: + case T_GREATER_GREATER: + newState = stream_op; + for (int i = m_currentState.size() - 1; i >= 0; --i) { + const int type = m_currentState.at(i).type; + if (type == arglist_open || type == braceinit_open) { // likely a left-shift instead + newState = -1; + break; + } + if (type == topmost_intro + || type == substatement_open + || type == defun_open + || type == namespace_open + || type == extern_open + || type == class_open + || type == brace_list_open) { + break; + } + } + break; + case T_LBRACKET: + newState = lambda_instroducer_or_subscribtion; + break; + } + + if (m_currentToken.isStringLiteral()) + newState = m_currentToken.kind() == T_RAW_STRING_LITERAL ? raw_string_open : string_open; + + if (newState != -1) { + if (alsoExpression) + enter(expression); + enter(newState); + return true; + } + + return false; +} + +bool CodeFormatter::tryDeclaration() +{ + const int kind = m_currentToken.kind(); + switch (kind) { + case T_Q_ENUMS: + case T_Q_PROPERTY: + case T_Q_PRIVATE_PROPERTY: + case T_Q_FLAGS: + case T_Q_GADGET: + case T_Q_OBJECT: + case T_Q_INTERFACES: + case T_Q_DECLARE_INTERFACE: + case T_Q_PRIVATE_SLOT: + enter(qt_like_macro); + return true; + case T_IDENTIFIER: + if (m_tokenIndex == 0) { + const QStringView tokenText = currentTokenText(); + if (tokenText.startsWith(QLatin1String("Q_")) + || tokenText.startsWith(QLatin1String("QT_")) + || tokenText.startsWith(QLatin1String("QML_")) + || tokenText.startsWith(QLatin1String("QDOC_"))) { + enter(qt_like_macro); + return true; + } + if (m_tokens.size() > 1 && m_tokens.at(1).kind() == T_COLON) { + enter(label); + return true; + } + } + Q_FALLTHROUGH(); + case T_CHAR: + case T_CHAR16_T: + case T_CHAR32_T: + case T_WCHAR_T: + case T_BOOL: + case T_SHORT: + case T_INT: + case T_LONG: + case T_SIGNED: + case T_UNSIGNED: + case T_FLOAT: + case T_DOUBLE: + case T_VOID: + case T_AUTO: + case T___TYPEOF__: + case T___ATTRIBUTE__: + case T___DECLSPEC: + case T_STATIC: + case T_FRIEND: + case T_CONST: + case T_VOLATILE: + case T_INLINE: + enter(declaration_start); + return true; + + case T_TEMPLATE: + enter(template_start); + return true; + + case T_NAMESPACE: + enter(namespace_start); + return true; + + case T_EXTERN: + enter(extern_start); + return true; + + case T_STRUCT: + case T_UNION: + case T_CLASS: + enter(class_start); + return true; + + case T_ENUM: + enter(enum_start); + return true; + + case T_USING: + enter(using_start); + return true; + + case T_PUBLIC: + case T_PRIVATE: + case T_PROTECTED: + case T_Q_SIGNALS: + if (m_currentState.top().type == class_open) { + enter(access_specifier_start); + return true; + } + return false; + + default: + return false; + } +} + +bool CodeFormatter::tryStatement() +{ + const int kind = m_currentToken.kind(); + if (tryDeclaration()) + return true; + switch (kind) { + case T_RETURN: + enter(return_statement); + enter(expression); + return true; + case T_FOR: + enter(for_statement); + return true; + case T_SWITCH: + enter(switch_statement); + return true; + case T_IF: + enter(if_statement); + return true; + case T_WHILE: + case T_Q_FOREACH: + enter(statement_with_condition); + return true; + case T_DO: + enter(do_statement); + enter(substatement); + return true; + case T_CASE: + case T_DEFAULT: + enter(case_start); + return true; + case T_LBRACE: + enter(block_open); + return true; + default: + return false; + } +} + +bool CodeFormatter::isBracelessState(int type) const +{ + return type == substatement + || type == if_statement + || type == else_clause + || type == statement_with_condition + || type == for_statement + || type == do_statement; +} + +const Token &CodeFormatter::tokenAt(int idx) const +{ + static const Token empty; + if (idx < 0 || idx >= m_tokens.size()) + return empty; + else + return m_tokens.at(idx); +} + +int CodeFormatter::column(int index) const +{ + int col = 0; + if (index > m_currentLine.length()) + index = m_currentLine.length(); + + const QChar tab = QLatin1Char('\t'); + + for (int i = 0; i < index; i++) { + if (m_currentLine[i] == tab) + col = ((col / m_tabSize) + 1) * m_tabSize; + else + col++; + } + return col; +} + +QStringView CodeFormatter::currentTokenText() const +{ + if (m_currentToken.utf16charsEnd() > m_currentLine.size()) + return QStringView(m_currentLine).mid(m_currentToken.utf16charsBegin()); + return QStringView(m_currentLine).mid(m_currentToken.utf16charsBegin(), m_currentToken.utf16chars()); +} + +void CodeFormatter::turnInto(int newState) +{ + leave(false); + enter(newState); +} + +void CodeFormatter::saveCurrentState(const QTextBlock &block) +{ + if (!block.isValid()) + return; + + BlockData blockData; + blockData.m_blockRevision = block.revision(); + blockData.m_beginState = m_beginState; + blockData.m_endState = m_currentState; + blockData.m_indentDepth = m_indentDepth; + blockData.m_paddingDepth = m_paddingDepth; + + QTextBlock saveableBlock(block); + saveBlockData(&saveableBlock, blockData); +} + +void CodeFormatter::restoreCurrentState(const QTextBlock &block) +{ + if (block.isValid()) { + BlockData blockData; + if (loadBlockData(block, &blockData)) { + m_indentDepth = blockData.m_indentDepth; + m_paddingDepth = blockData.m_paddingDepth; + m_currentState = blockData.m_endState; + m_beginState = m_currentState; + return; + } + } + + m_currentState = initialState(); + m_beginState = m_currentState; + m_indentDepth = 0; + m_paddingDepth = 0; +} + +QStack<CodeFormatter::State> CodeFormatter::initialState() +{ + static QStack<CodeFormatter::State> initialState; + if (initialState.isEmpty()) + initialState.push(State(topmost_intro, 0, 0)); + return initialState; +} + +int CodeFormatter::tokenizeBlock(const QTextBlock &block, bool *endedJoined) +{ + int startState = loadLexerState(block.previous()); + if (block.blockNumber() == 0) + startState = 0; + QTC_ASSERT(startState != -1, return 0); + + LanguageFeatures features; + features.qtEnabled = true; + features.qtMocRunEnabled = true; + features.qtKeywordsEnabled = true; + features.cxxEnabled = true; + features.objCEnabled = true; + features.cxx11Enabled = true; + features.cxx14Enabled = true; + + SimpleLexer tokenize; + tokenize.setLanguageFeatures(features); + + m_currentLine = block.text(); + // to determine whether a line was joined, Tokenizer needs a + // newline character at the end + m_currentLine.append(QLatin1Char('\n')); + m_tokens = tokenize(m_currentLine, startState); + + if (endedJoined) + *endedJoined = tokenize.endedJoined(); + + const int lexerState = tokenize.state(); + TextDocumentLayout::setLexerState(block, lexerState); + return lexerState; +} + +void CodeFormatter::dump() const +{ + QMetaEnum metaEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("StateType")); + + qDebug() << "Current token index" << m_tokenIndex; + qDebug() << "Current state:"; + foreach (const State &s, m_currentState) { + qDebug() << metaEnum.valueToKey(s.type) << s.savedIndentDepth << s.savedPaddingDepth; + } + qDebug() << "Current indent depth:" << m_indentDepth; + qDebug() << "Current padding depth:" << m_paddingDepth; +} + + +namespace Internal { +class CppCodeFormatterData: public CodeFormatterData +{ +public: + CodeFormatter::BlockData m_data; +}; +} // namespace Internal + +using namespace Internal; + +QtStyleCodeFormatter::QtStyleCodeFormatter() = default; + +QtStyleCodeFormatter::QtStyleCodeFormatter(const TabSettings &tabSettings, + const CppCodeStyleSettings &settings) + : m_tabSettings(tabSettings) + , m_styleSettings(settings) +{ + setTabSize(tabSettings.m_tabSize); +} + +void QtStyleCodeFormatter::setTabSettings(const TabSettings &tabSettings) +{ + m_tabSettings = tabSettings; + setTabSize(tabSettings.m_tabSize); +} + +void QtStyleCodeFormatter::setCodeStyleSettings(const CppCodeStyleSettings &settings) +{ + m_styleSettings = settings; +} + +void QtStyleCodeFormatter::saveBlockData(QTextBlock *block, const BlockData &data) const +{ + TextBlockUserData *userData = TextDocumentLayout::userData(*block); + auto cppData = static_cast<CppCodeFormatterData *>(userData->codeFormatterData()); + if (!cppData) { + cppData = new CppCodeFormatterData; + userData->setCodeFormatterData(cppData); + } + cppData->m_data = data; +} + +bool QtStyleCodeFormatter::loadBlockData(const QTextBlock &block, BlockData *data) const +{ + TextBlockUserData *userData = TextDocumentLayout::textUserData(block); + if (!userData) + return false; + auto cppData = static_cast<const CppCodeFormatterData *>(userData->codeFormatterData()); + if (!cppData) + return false; + + *data = cppData->m_data; + return true; +} + +void QtStyleCodeFormatter::saveLexerState(QTextBlock *block, int state) const +{ + TextDocumentLayout::setLexerState(*block, state); +} + +int QtStyleCodeFormatter::loadLexerState(const QTextBlock &block) const +{ + return TextDocumentLayout::lexerState(block); +} + +void QtStyleCodeFormatter::addContinuationIndent(int *paddingDepth) const +{ + if (*paddingDepth == 0) + *paddingDepth = 2*m_tabSettings.m_indentSize; + else + *paddingDepth += m_tabSettings.m_indentSize; +} + +void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const +{ + const State &parentState = state(); + const Token &tk = currentToken(); + const bool firstToken = (tokenIndex() == 0); + const bool lastToken = (tokenIndex() == tokenCount() - 1); + const int tokenPosition = column(tk.utf16charsBegin()); + const int nextTokenPosition = lastToken ? tokenPosition + tk.utf16chars() + : column(tokenAt(tokenIndex() + 1).utf16charsBegin()); + const int spaceOrNextTokenPosition = lastToken ? tokenPosition + tk.utf16chars() + 1 + : nextTokenPosition; + + if (shouldClearPaddingOnEnter(newState)) + *paddingDepth = 0; + + switch (newState) { + case extern_start: + case namespace_start: + if (firstToken) { + *savedIndentDepth = tokenPosition; + *indentDepth = tokenPosition; + } + break; + + case enum_start: + case class_start: + if (firstToken) { + *savedIndentDepth = tokenPosition; + *indentDepth = tokenPosition; + } + *paddingDepth = 2*m_tabSettings.m_indentSize; + break; + + case template_param: + if (!lastToken) + *paddingDepth = nextTokenPosition-*indentDepth; + else + addContinuationIndent(paddingDepth); + break; + + case statement_with_condition: + case for_statement: + case switch_statement: + case if_statement: + case return_statement: + if (firstToken) + *indentDepth = *savedIndentDepth = tokenPosition; + *paddingDepth = 2*m_tabSettings.m_indentSize; + break; + + case declaration_start: + if (firstToken) { + *savedIndentDepth = tokenPosition; + *indentDepth = *savedIndentDepth; + } + // continuation indent in function bodies only, to not indent + // after the return type in "void\nfoo() {}" + for (int i = 0; state(i).type != topmost_intro; ++i) { + if (state(i).type == defun_open) { + *paddingDepth = 2*m_tabSettings.m_indentSize; + break; + } + } + break; + + case assign_open: + if (parentState.type == assign_open_or_initializer) + break; + Q_FALLTHROUGH(); + case assign_open_or_initializer: + if (!lastToken && m_styleSettings.alignAssignments) + *paddingDepth = nextTokenPosition-*indentDepth; + else + *paddingDepth = 2*m_tabSettings.m_indentSize; + break; + + case arglist_open: + case condition_paren_open: + case member_init_nest_open: + if (!lastToken) + *paddingDepth = nextTokenPosition-*indentDepth; + else + addContinuationIndent(paddingDepth); + break; + + case ternary_op: + if (!lastToken) + *paddingDepth = spaceOrNextTokenPosition-*indentDepth; + else + addContinuationIndent(paddingDepth); + break; + + case stream_op: + *paddingDepth = spaceOrNextTokenPosition-*indentDepth; + break; + case stream_op_cont: + if (firstToken) + *savedPaddingDepth = *paddingDepth = spaceOrNextTokenPosition-*indentDepth; + break; + + case member_init_open: + // undo the continuation indent of the parent + *savedPaddingDepth = 0; + + // The paddingDepth is the expected location of the ',' and + // identifiers are padded +2 from that in member_init_expected. + if (firstToken) + *paddingDepth = tokenPosition-*indentDepth; + else + *paddingDepth = m_tabSettings.m_indentSize - 2; + break; + + case member_init_expected: + *paddingDepth += 2; + break; + + case member_init: + // make continuation indents relative to identifier start + *paddingDepth = tokenPosition - *indentDepth; + if (firstToken) { + // see comment in member_init_open + *savedPaddingDepth = *paddingDepth - 2; + } + break; + + case case_cont: + if (m_styleSettings.indentStatementsRelativeToSwitchLabels) + *indentDepth += m_tabSettings.m_indentSize; + break; + + case namespace_open: + case class_open: + case enum_open: + case defun_open: { + // undo the continuation indent of the parent + *savedPaddingDepth = 0; + + // whether the { is followed by a non-comment token + bool followedByData = (!lastToken && !tokenAt(tokenIndex() + 1).isComment()); + if (followedByData) + *savedPaddingDepth = tokenPosition-*indentDepth; // pad the } to align with the { + + if (newState == class_open) { + if (m_styleSettings.indentAccessSpecifiers + || m_styleSettings.indentDeclarationsRelativeToAccessSpecifiers) + *indentDepth += m_tabSettings.m_indentSize; + if (m_styleSettings.indentAccessSpecifiers && m_styleSettings.indentDeclarationsRelativeToAccessSpecifiers) + *indentDepth += m_tabSettings.m_indentSize; + } else if (newState == defun_open) { + if (m_styleSettings.indentFunctionBody || m_styleSettings.indentFunctionBraces) + *indentDepth += m_tabSettings.m_indentSize; + if (m_styleSettings.indentFunctionBody && m_styleSettings.indentFunctionBraces) + *indentDepth += m_tabSettings.m_indentSize; + } else if (newState == namespace_open) { + if (m_styleSettings.indentNamespaceBody || m_styleSettings.indentNamespaceBraces) + *indentDepth += m_tabSettings.m_indentSize; + if (m_styleSettings.indentNamespaceBody && m_styleSettings.indentNamespaceBraces) + *indentDepth += m_tabSettings.m_indentSize; + } else { + *indentDepth += m_tabSettings.m_indentSize; + } + + if (followedByData) + *paddingDepth = nextTokenPosition-*indentDepth; + break; + } + + case substatement_open: + // undo parent continuation indent + *savedPaddingDepth = 0; + + if (parentState.type == switch_statement) { + if (m_styleSettings.indentSwitchLabels) + *indentDepth += m_tabSettings.m_indentSize; + } else { + if (m_styleSettings.indentBlockBody || m_styleSettings.indentBlockBraces) + *indentDepth += m_tabSettings.m_indentSize; + if (m_styleSettings.indentBlockBody && m_styleSettings.indentBlockBraces) + *indentDepth += m_tabSettings.m_indentSize; + } + break; + + case brace_list_open: + if (!lastToken) { + if (parentState.type == assign_open_or_initializer) + *savedPaddingDepth = tokenPosition-*indentDepth; + *paddingDepth = nextTokenPosition-*indentDepth; + } else { + // avoid existing continuation indents + if (parentState.type == assign_open_or_initializer) + *savedPaddingDepth = state(1).savedPaddingDepth; + *paddingDepth = *savedPaddingDepth + m_tabSettings.m_indentSize; + } + break; + + case block_open: + // case_cont already adds some indent, revert it for a block + if (parentState.type == case_cont) { + *indentDepth = parentState.savedIndentDepth; + if (m_styleSettings.indentBlocksRelativeToSwitchLabels) + *indentDepth += m_tabSettings.m_indentSize; + } + + if (m_styleSettings.indentBlockBody) + *indentDepth += m_tabSettings.m_indentSize; + break; + + case condition_open: + // undo the continuation indent of the parent + *paddingDepth = parentState.savedPaddingDepth; + *savedPaddingDepth = *paddingDepth; + + // fixed extra indent when continuing 'if (', but not for 'else if (' + if (m_styleSettings.extraPaddingForConditionsIfConfusingAlign + && nextTokenPosition-*indentDepth <= m_tabSettings.m_indentSize) + *paddingDepth = 2*m_tabSettings.m_indentSize; + else + *paddingDepth = nextTokenPosition-*indentDepth; + break; + + case substatement: + // undo the continuation indent of the parent + *savedPaddingDepth = 0; + + break; + + case maybe_else: { + // set indent to outermost braceless savedIndent + int outermostBraceless = 0; + while (isBracelessState(state(outermostBraceless).type)) + ++outermostBraceless; + *indentDepth = state(outermostBraceless - 1).savedIndentDepth; + // this is where the else should go, if one appears - aligned to if_statement + *savedIndentDepth = state().savedIndentDepth; + } break; + + case for_statement_paren_open: + *paddingDepth = nextTokenPosition - *indentDepth; + break; + + case multiline_comment_start: + *indentDepth = tokenPosition + 2; // nextTokenPosition won't work + break; + + case multiline_comment_cont: + *indentDepth = tokenPosition; + break; + + case cpp_macro: + case cpp_macro_cont: + *indentDepth = m_tabSettings.m_indentSize; + break; + + case string_open: + case raw_string_open: + *paddingDepth = tokenPosition - *indentDepth; + break; + } + + // ensure padding and indent are >= 0 + *indentDepth = qMax(0, *indentDepth); + *savedIndentDepth = qMax(0, *savedIndentDepth); + *paddingDepth = qMax(0, *paddingDepth); + *savedPaddingDepth = qMax(0, *savedPaddingDepth); +} + +void QtStyleCodeFormatter::adjustIndent(const Tokens &tokens, int lexerState, int *indentDepth, int *paddingDepth) const +{ + State topState = state(); + State previousState = state(1); + + const bool topWasMaybeElse = (topState.type == maybe_else); + if (topWasMaybeElse) { + int outermostBraceless = 1; + while (state(outermostBraceless).type != invalid && isBracelessState(state(outermostBraceless).type)) + ++outermostBraceless; + + topState = state(outermostBraceless); + previousState = state(outermostBraceless + 1); + } + + + // adjusting the indentDepth here instead of in enter() gives 'else if' the correct indentation + // ### could be moved? + switch (topState.type) { + case substatement: + *indentDepth += m_tabSettings.m_indentSize; + break; + // keep user-adjusted indent in multiline comments + case multiline_comment_start: + case multiline_comment_cont: + if (!tokens.isEmpty()) { + *indentDepth = column(tokens.at(0).utf16charsBegin()); + return; + } + break; + case string_open: + case raw_string_open: + if (!tokenAt(0).isStringLiteral()) { + *paddingDepth = topState.savedPaddingDepth; + topState = previousState; + previousState = state(2); + } + break; + } + + const int kind = tokenAt(0).kind(); + switch (kind) { + case T_POUND: *indentDepth = 0; break; + case T_COLON: + // ### ok for constructor initializer lists - what about ? and bitfields? + if (topState.type == expression && previousState.type == declaration_start) { + *paddingDepth = m_tabSettings.m_indentSize; + } else if (topState.type == ternary_op) { + if (*paddingDepth >= 2) + *paddingDepth -= 2; + else + *paddingDepth = 0; + } + break; + case T_LBRACE: { + if (topState.type == case_cont) { + *indentDepth = topState.savedIndentDepth; + if (m_styleSettings.indentBlocksRelativeToSwitchLabels) + *indentDepth += m_tabSettings.m_indentSize; + *paddingDepth = 0; + // function definition - argument list is expression state + // or constructor + } else if ((topState.type == expression && previousState.type == declaration_start) + || topState.type == member_init || topState.type == member_init_open) { + // the declaration_start indent is the base + if (topState.type == member_init) + *indentDepth = state(2).savedIndentDepth; + else + *indentDepth = previousState.savedIndentDepth; + if (m_styleSettings.indentFunctionBraces) + *indentDepth += m_tabSettings.m_indentSize; + *paddingDepth = 0; + } else if (topState.type == class_start) { + *indentDepth = topState.savedIndentDepth; + if (m_styleSettings.indentClassBraces) + *indentDepth += m_tabSettings.m_indentSize; + *paddingDepth = 0; + } else if (topState.type == enum_start) { + *indentDepth = topState.savedIndentDepth; + if (m_styleSettings.indentEnumBraces) + *indentDepth += m_tabSettings.m_indentSize; + *paddingDepth = 0; + } else if (topState.type == namespace_start) { + *indentDepth = topState.savedIndentDepth; + if (m_styleSettings.indentNamespaceBraces) + *indentDepth += m_tabSettings.m_indentSize; + *paddingDepth = 0; + } else if (topState.type == substatement) { + *indentDepth = topState.savedIndentDepth; + if (m_styleSettings.indentBlockBraces) + *indentDepth += m_tabSettings.m_indentSize; + *paddingDepth = 0; + } else if (topState.type != defun_open + && topState.type != block_open + && topState.type != substatement_open + && topState.type != brace_list_open + && topState.type != arglist_open + && !topWasMaybeElse) { + *indentDepth = topState.savedIndentDepth; + *paddingDepth = 0; + } + + break; + } + case T_RBRACE: { + if (topState.type == block_open && previousState.type == case_cont) { + *indentDepth = previousState.savedIndentDepth; + *paddingDepth = previousState.savedPaddingDepth; + if (m_styleSettings.indentBlocksRelativeToSwitchLabels) + *indentDepth += m_tabSettings.m_indentSize; + break; + } + for (int i = 0; state(i).type != topmost_intro; ++i) { + const int type = state(i).type; + if (type == class_open + || type == namespace_open + || type == extern_open + || type == enum_open + || type == defun_open + || type == substatement_open + || type == brace_list_open + || type == block_open) { + *indentDepth = state(i).savedIndentDepth; + *paddingDepth = state(i).savedPaddingDepth; + if ((type == defun_open && m_styleSettings.indentFunctionBraces) + || (type == class_open && m_styleSettings.indentClassBraces) + || (type == namespace_open && m_styleSettings.indentNamespaceBraces) + || (type == enum_open && m_styleSettings.indentEnumBraces) + || (type == substatement_open && m_styleSettings.indentBlockBraces)) + *indentDepth += m_tabSettings.m_indentSize; + break; + } + } + break; + } + // Disabled for now, see QTCREATORBUG-1825. It makes extending if conditions + // awkward: inserting a newline just before the ) shouldn't align to 'if'. + //case T_RPAREN: + // if (topState.type == condition_open) { + // *indentDepth = previousState.savedIndentDepth; + // } + // break; + case T_DEFAULT: + case T_CASE: { + for (int i = 0; state(i).type != topmost_intro; ++i) { + const int type = state(i).type; + if (type == switch_statement) { + *indentDepth = state(i).savedIndentDepth; + if (m_styleSettings.indentSwitchLabels) + *indentDepth += m_tabSettings.m_indentSize; + break; + } else if (type == case_cont) { + *indentDepth = state(i).savedIndentDepth; + break; + } + } + break; + } + case T_PUBLIC: + case T_PRIVATE: + case T_PROTECTED: + case T_Q_SIGNALS: + if (m_styleSettings.indentDeclarationsRelativeToAccessSpecifiers + && topState.type == class_open) { + if (tokenAt(1).is(T_COLON) || tokenAt(2).is(T_COLON) + || (tokenAt(tokenCount() - 1).is(T_COLON) && (tokenAt(1).is(T___ATTRIBUTE__) || tokenAt(1).is(T___DECLSPEC)))) { + *indentDepth = topState.savedIndentDepth; + if (m_styleSettings.indentAccessSpecifiers) + *indentDepth += m_tabSettings.m_indentSize; + } + } + break; + case T_ELSE: + if (topWasMaybeElse) + *indentDepth = state().savedIndentDepth; // topSavedIndent is actually the previous + break; + case T_LESS_LESS: + case T_GREATER_GREATER: + if (topState.type == stream_op || topState.type == stream_op_cont) { + if (*paddingDepth >= 3) + *paddingDepth -= 3; // to align << with << + else + *paddingDepth = 0; + } + break; + case T_COMMENT: + case T_DOXY_COMMENT: + case T_CPP_COMMENT: + case T_CPP_DOXY_COMMENT: + // unindent the last line of a comment + if ((topState.type == multiline_comment_cont + || topState.type == multiline_comment_start) + && (kind == T_COMMENT || kind == T_DOXY_COMMENT) + && (lexerState == T_EOF_SYMBOL + || tokens.size() != 1)) { + if (*indentDepth >= m_tabSettings.m_indentSize) + *indentDepth -= m_tabSettings.m_indentSize; + else + *indentDepth = 0; + } + break; + case T_IDENTIFIER: + if (topState.type == substatement + || topState.type == substatement_open + || topState.type == case_cont + || topState.type == block_open + || topState.type == defun_open) { + if (tokens.size() > 1 && tokens.at(1).kind() == T_COLON) // label? + *indentDepth = 0; + } + break; + case T_BREAK: + case T_CONTINUE: + case T_RETURN: + if (topState.type == case_cont) { + *indentDepth = topState.savedIndentDepth; + if (m_styleSettings.indentControlFlowRelativeToSwitchLabels) + *indentDepth += m_tabSettings.m_indentSize; + } + break; + } + // ensure padding and indent are >= 0 + *indentDepth = qMax(0, *indentDepth); + *paddingDepth = qMax(0, *paddingDepth); +} + +bool QtStyleCodeFormatter::shouldClearPaddingOnEnter(int state) +{ + switch (state) { + case defun_open: + case class_start: + case class_open: + case enum_start: + case enum_open: + case namespace_start: + case namespace_open: + case extern_start: + case extern_open: + case template_start: + case if_statement: + case else_clause: + case for_statement: + case switch_statement: + case statement_with_condition: + case do_statement: + case return_statement: + case block_open: + case substatement_open: + case substatement: + return true; + } + return false; +} + +} // namespace CppEditor |
