cppcodeformatter.h 11.1 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Christian Kamm's avatar
Christian Kamm committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3 4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
Christian Kamm's avatar
Christian Kamm committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
Christian Kamm's avatar
Christian Kamm committed
7
**
hjk's avatar
hjk committed
8 9 10 11
** 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
Eike Ziller's avatar
Eike Ziller committed
12 13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
Christian Kamm's avatar
Christian Kamm committed
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
Christian Kamm's avatar
Christian Kamm committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25 26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
Christian Kamm's avatar
Christian Kamm committed
30

31 32 33 34
#ifndef CPPCODEFORMATTER_H
#define CPPCODEFORMATTER_H

#include "cpptools_global.h"
35
#include "cppcodestylesettings.h"
36

37
#include <texteditor/tabsettings.h>
38 39

#include <cplusplus/SimpleLexer.h>
40

41 42 43
#include <QStack>
#include <QList>
#include <QVector>
44 45 46 47 48 49

QT_BEGIN_NAMESPACE
class QTextDocument;
class QTextBlock;
QT_END_NAMESPACE

50
namespace CppTools {
51
namespace Internal { class CppCodeFormatterData; }
52 53 54

class CPPTOOLS_EXPORT CodeFormatter
{
55
    Q_GADGET
56 57 58 59
public:
    CodeFormatter();
    virtual ~CodeFormatter();

60 61
    // updates all states up until block if necessary
    // it is safe to call indentFor on block afterwards
62
    void updateStateUntil(const QTextBlock &block);
63 64 65 66

    // calculates the state change introduced by changing a single line
    void updateLineStateChange(const QTextBlock &block);

67 68
    void indentFor(const QTextBlock &block, int *indent, int *padding);
    void indentForNewLineAfter(const QTextBlock &block, int *indent, int *padding);
69

70 71
    void setTabSize(int tabSize);

72
    void invalidateCache(QTextDocument *document);
Christian Kamm's avatar
Christian Kamm committed
73

74
protected:
75
    virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const = 0;
76
    virtual void adjustIndent(const CPlusPlus::Tokens &tokens, int lexerState, int *indentDepth, int *paddingDepth) const = 0;
77

78 79 80 81 82 83 84 85 86
    class State;
    class BlockData
    {
    public:
        BlockData();

        QStack<State> m_beginState;
        QStack<State> m_endState;
        int m_indentDepth;
87
        int m_paddingDepth;
88 89 90 91 92 93 94 95 96
        int m_blockRevision;
    };

    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;

97
public: // must be public to make Q_GADGET introspection work
98 99 100 101 102 103 104 105 106 107 108 109
    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
Christian Kamm's avatar
Christian Kamm committed
110
        label, // after an identifier followed by a colon
111 112 113 114 115 116

        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.
117

118 119
        access_specifier_start, // after 'private', 'protected' etc.

120
        member_init_open, // After ':' that starts a member initialization list.
121 122
        member_init_expected, // At the start and after every ',' in member_init_open
        member_init, // After an identifier in member_init_expected
123
        member_init_nest_open, // After '(' or '{' in member_init.
124 125

        enum_start, // After 'enum'
126 127
        enum_open, // Brace that opens a enum declaration.
        brace_list_open, // Open brace nested inside an enum or for a static array list.
128 129 130 131

        namespace_start, // after the namespace token, before the opening brace.
        namespace_open, // Brace that opens a C++ namespace block.

132 133 134
        extern_start, // after the extern token, before the opening brace.
        extern_open, // Brace that opens a C++ extern block.

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
        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.
164 165
        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
166
        ternary_op, // The ? : operator
167
        braceinit_open, // after '{' in an expression context
168 169 170 171 172 173 174

        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 '= {'
Flex Ferrum's avatar
Flex Ferrum committed
175 176 177 178 179 180 181 182
        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
183 184
        lambda_statement,                // just after '{' when previous state is lambda_declarator or lambda_declarator_or_expression
        string_open
Flex Ferrum's avatar
Flex Ferrum committed
185

186
    };
187
    Q_ENUMS(StateType)
188

189
protected:
190 191
    class State {
    public:
192 193
        State()
            : savedIndentDepth(0)
194
            , savedPaddingDepth(0)
195 196 197
            , type(0)
        {}

198 199 200
        State(quint8 ty, quint16 savedIndentDepth, qint16 savedPaddingDepth)
            : savedIndentDepth(savedIndentDepth)
            , savedPaddingDepth(savedPaddingDepth)
201 202 203 204
            , type(ty)
        {}

        quint16 savedIndentDepth;
205
        quint16 savedPaddingDepth;
206 207 208 209
        quint8 type;

        bool operator==(const State &other) const {
            return type == other.type
210 211
                && savedIndentDepth == other.savedIndentDepth
                && savedPaddingDepth == other.savedPaddingDepth;
212 213 214 215
        }
    };

    State state(int belowTop = 0) const;
216
    const QVector<State> &newStatesThisLine() const;
217
    int tokenIndex() const;
218
    int tokenCount() const;
219 220
    const CPlusPlus::Token &currentToken() const;
    const CPlusPlus::Token &tokenAt(int idx) const;
221
    int column(int position) const;
222 223 224

    bool isBracelessState(int type) const;

225 226
    void dump() const;

227 228
private:
    void recalculateStateAfter(const QTextBlock &block);
229 230
    void saveCurrentState(const QTextBlock &block);
    void restoreCurrentState(const QTextBlock &block);
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

    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;
251
    QStack<State> m_newStates;
252

253
    CPlusPlus::Tokens m_tokens;
254 255 256 257 258
    QString m_currentLine;
    CPlusPlus::Token m_currentToken;
    int m_tokenIndex;

    int m_indentDepth;
259
    int m_paddingDepth;
260

261 262
    int m_tabSize;

263 264 265 266 267 268 269
    friend class Internal::CppCodeFormatterData;
};

class CPPTOOLS_EXPORT QtStyleCodeFormatter : public CodeFormatter
{
public:
    QtStyleCodeFormatter();
270 271
    QtStyleCodeFormatter(const TextEditor::TabSettings &tabSettings,
                         const CppCodeStyleSettings &settings);
272

273 274
    void setTabSettings(const TextEditor::TabSettings &tabSettings);
    void setCodeStyleSettings(const CppCodeStyleSettings &settings);
275

276
protected:
277
    virtual void onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const;
278
    virtual void adjustIndent(const CPlusPlus::Tokens &tokens, int lexerState, int *indentDepth, int *paddingDepth) const;
279

280 281 282 283 284 285
    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;

286 287
    static bool shouldClearPaddingOnEnter(int state);

288
private:
289 290
    void addContinuationIndent(int *paddingDepth) const;

291 292
    TextEditor::TabSettings m_tabSettings;
    CppCodeStyleSettings m_styleSettings;
293 294 295 296 297
};

} // namespace CppTools

#endif // CPPCODEFORMATTER_H