diff options
Diffstat (limited to 'src/plugins/cpptools/cppcodeformatter.cpp')
-rw-r--r-- | src/plugins/cpptools/cppcodeformatter.cpp | 1707 |
1 files changed, 0 insertions, 1707 deletions
diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp deleted file mode 100644 index 639084a3ca..0000000000 --- a/src/plugins/cpptools/cppcodeformatter.cpp +++ /dev/null @@ -1,1707 +0,0 @@ -/**************************************************************************** -** -** 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 CppTools; -using namespace TextEditor; -using namespace CppTools::Internal; - -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 CppTools { -namespace Internal { - class CppCodeFormatterData: public CodeFormatterData - { - public: - CodeFormatter::BlockData m_data; - }; -} -} - -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; -} |