-
Nikolai Kosjar authored
...from coverity scan. Change-Id: I7f4c3de39279cfffab2246aa84ae2ac13916bd1e Reviewed-by:
Robert Loehning <robert.loehning@qt.io>
Nikolai Kosjar authored...from coverity scan. Change-Id: I7f4c3de39279cfffab2246aa84ae2ac13916bd1e Reviewed-by:
Robert Loehning <robert.loehning@qt.io>
cppcodeformatter.h 10.53 KiB
/****************************************************************************
**
** 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.
**
****************************************************************************/
#pragma once
#include "cpptools_global.h"
#include "cppcodestylesettings.h"
#include <texteditor/tabsettings.h>
#include <cplusplus/SimpleLexer.h>
#include <QStack>
#include <QList>
#include <QVector>
QT_BEGIN_NAMESPACE
class QTextDocument;
class QTextBlock;
QT_END_NAMESPACE
namespace CppTools {
namespace Internal { class CppCodeFormatterData; }
class CPPTOOLS_EXPORT CodeFormatter
{
Q_GADGET
public:
virtual ~CodeFormatter();
// updates all states up until block if necessary
// it is safe to call indentFor on block afterwards
void updateStateUntil(const QTextBlock &block);
// calculates the state change introduced by changing a single line
void updateLineStateChange(const QTextBlock &block);
void indentFor(const QTextBlock &block, int *indent, int *padding);
void indentForNewLineAfter(const QTextBlock &block, int *indent, int *padding);
void setTabSize(int tabSize);
void invalidateCache(QTextDocument *document);
protected:
virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const = 0;
virtual void adjustIndent(const CPlusPlus::Tokens &tokens, int lexerState, int *indentDepth, int *paddingDepth) const = 0;
class State;
class BlockData
{
public:
QStack<State> m_beginState;
QStack<State> m_endState;
int m_indentDepth = 0;
int m_paddingDepth = 0;
int m_blockRevision = -1;
};
virtual void saveBlockData(QTextBlock *block, const BlockData &data) const = 0;
virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const = 0;
virtual void saveLexerState(QTextBlock *block, int state) const = 0;
virtual int loadLexerState(const QTextBlock &block) const = 0;
public: // must be public to make Q_GADGET introspection work
enum StateType {
invalid = 0,
topmost_intro, // The first line in a "topmost" definition.
multiline_comment_start, // Inside the first line of a multi-line C style block comment.
multiline_comment_cont, // Inside the following lines of a multi-line C style block comment.
cpp_macro_start, // After the '#' token
cpp_macro, // The start of a C preprocessor macro definition.
cpp_macro_cont, // Subsequent lines of a multi-line C preprocessor macro definition.
cpp_macro_conditional, // Special marker used for separating saved from current state when dealing with #ifdef
qt_like_macro, // after an identifier starting with Q_ or QT_ at the beginning of the line
label, // after an identifier followed by a colon
defun_open, // Brace that opens a top-level function definition.
using_start, // right after the "using" token
class_start, // after the 'class' token
class_open, // Brace that opens a class definition.
access_specifier_start, // after 'private', 'protected' etc.
member_init_open, // After ':' that starts a member initialization list.
member_init_expected, // At the start and after every ',' in member_init_open
member_init, // After an identifier in member_init_expected
member_init_nest_open, // After '(' or '{' in member_init.
enum_start, // After 'enum'
enum_open, // Brace that opens a enum declaration.
brace_list_open, // Open brace nested inside an enum or for a static array list.
namespace_start, // after the namespace token, before the opening brace.
namespace_open, // Brace that opens a C++ namespace block.
extern_start, // after the extern token, before the opening brace.
extern_open, // Brace that opens a C++ extern block.
declaration_start, // shifted a token which could start a declaration.
operator_declaration, // after 'operator' in declaration_start
template_start, // after the 'template' token
template_param, // after the '<' in a template_start
if_statement, // After 'if'
maybe_else, // after the first substatement in an if
else_clause, // The else line of an if-else construct.
for_statement, // After the 'for' token
for_statement_paren_open, // While inside the (...)
for_statement_init, // The initializer part of the for statement
for_statement_condition, // The condition part of the for statement
for_statement_expression, // The expression part of the for statement
switch_statement, // After 'switch' token
case_start, // after a 'case' or 'default' token
case_cont, // after the colon in a case/default
statement_with_condition, // A statement that takes a condition after the start token.
do_statement, // After 'do' token
return_statement, // After 'return'
block_open, // Statement block open brace.
substatement, // The first line after a conditional or loop construct.
substatement_open, // The brace that opens a substatement block.
arglist_open, // after the lparen. TODO: check if this is enough.
stream_op, // After a '<<' or '>>' in a context where it's likely a stream operator.
stream_op_cont, // When finding another stream operator in stream_op
ternary_op, // The ? : operator
braceinit_open, // after '{' in an expression context
condition_open, // Start of a condition in 'if', 'while', entered after opening paren
condition_paren_open, // After an lparen in a condition
assign_open, // after an assignment token
expression, // after a '=' in a declaration_start once we're sure it's not '= {'
assign_open_or_initializer, // after a '=' in a declaration start
lambda_instroducer_or_subscribtion, // just after '[' or in cases '[]' and '[id]' when we're not sure in the exact kind of expression
lambda_declarator_expected, // just after ']' in lambda_introducer_or_subscribtion
lambda_declarator_or_expression, // just after '](' when previous state is 'lambda_instroducer_or_subscribtion'
lambda_statement_expected,
lambda_instroducer, // when '=', '&' or ',' occurred within '[]'
lambda_declarator, // just after ']' when previous state is lambda_introducer
lambda_statement, // just after '{' when previous state is lambda_declarator or lambda_declarator_or_expression
string_open
};
Q_ENUMS(StateType)
protected:
class State {
public:
State() = default;
State(quint8 ty, quint16 savedIndentDepth, quint16 savedPaddingDepth)
: savedIndentDepth(savedIndentDepth)
, savedPaddingDepth(savedPaddingDepth)
, type(ty)
{}
quint16 savedIndentDepth = 0;
quint16 savedPaddingDepth = 0;
quint8 type = 0;
bool operator==(const State &other) const {
return type == other.type
&& savedIndentDepth == other.savedIndentDepth
&& savedPaddingDepth == other.savedPaddingDepth;
}
};
State state(int belowTop = 0) const;
int tokenIndex() const;
int tokenCount() const;
const CPlusPlus::Token ¤tToken() const;
const CPlusPlus::Token &tokenAt(int idx) const;
int column(int position) const;
bool isBracelessState(int type) const;
void dump() const;
private:
void recalculateStateAfter(const QTextBlock &block);
void saveCurrentState(const QTextBlock &block);
void restoreCurrentState(const QTextBlock &block);
QStringRef currentTokenText() const;
int tokenizeBlock(const QTextBlock &block, bool *endedJoined = 0);
void turnInto(int newState);
bool tryExpression(bool alsoExpression = false);
bool tryDeclaration();
bool tryStatement();
void enter(int newState);
void leave(bool statementDone = false);
void correctIndentation(const QTextBlock &block);
private:
static QStack<State> initialState();
QStack<State> m_beginState;
QStack<State> m_currentState;
QStack<State> m_newStates;
CPlusPlus::Tokens m_tokens;
QString m_currentLine;
CPlusPlus::Token m_currentToken;
int m_tokenIndex = 0;
int m_indentDepth = 0;
int m_paddingDepth = 0;
int m_tabSize = 4;
friend class Internal::CppCodeFormatterData;
};
class CPPTOOLS_EXPORT QtStyleCodeFormatter : public CodeFormatter
{
public:
QtStyleCodeFormatter();
QtStyleCodeFormatter(const TextEditor::TabSettings &tabSettings,
const CppCodeStyleSettings &settings);
void setTabSettings(const TextEditor::TabSettings &tabSettings);
void setCodeStyleSettings(const CppCodeStyleSettings &settings);
protected:
virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const;
virtual void adjustIndent(const CPlusPlus::Tokens &tokens, int lexerState, int *indentDepth, int *paddingDepth) const;
virtual void saveBlockData(QTextBlock *block, const BlockData &data) const;
virtual bool loadBlockData(const QTextBlock &block, BlockData *data) const;
virtual void saveLexerState(QTextBlock *block, int state) const;
virtual int loadLexerState(const QTextBlock &block) const;
static bool shouldClearPaddingOnEnter(int state);
private:
void addContinuationIndent(int *paddingDepth) const;
TextEditor::TabSettings m_tabSettings;
CppCodeStyleSettings m_styleSettings;
};
} // namespace CppTools