cppcodeformatter.cpp 54.7 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Christian Kamm's avatar
Christian Kamm committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
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
12
13
14
** 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 Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
Christian Kamm's avatar
Christian Kamm committed
15
16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
18
19
20
21
22
23
24
25
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
Christian Kamm's avatar
Christian Kamm committed
29

30
31
32
#include "cppcodeformatter.h"

#include <texteditor/basetextdocumentlayout.h>
33
34
#include <cplusplus/Lexer.h>

35
#include <utils/qtcassert.h>
36

37
38
39
40
#include <QDebug>
#include <QMetaEnum>
#include <QTextDocument>
#include <QTextBlock>
41
42
43
44
45
46

using namespace CPlusPlus;
using namespace CppTools;
using namespace TextEditor;
using namespace CppTools::Internal;

47
48
49
50
51
CodeFormatter::BlockData::BlockData()
    : m_blockRevision(-1)
{
}

52
CodeFormatter::CodeFormatter()
53
    : m_indentDepth(0)
54
    , m_paddingDepth(0)
55
    , m_tabSize(4)
56
57
58
59
60
61
62
{
}

CodeFormatter::~CodeFormatter()
{
}

63
64
65
66
67
void CodeFormatter::setTabSize(int tabSize)
{
    m_tabSize = tabSize;
}

68
69
void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
{
70
    restoreCurrentState(block.previous());
71
72

    bool endedJoined = false;
73
74
    // Discard newline expected bit from state
    const int lexerState = tokenizeBlock(block, &endedJoined) & ~0x80;
75
    m_tokenIndex = 0;
76
    m_newStates.clear();
77
78
79
80
81
82
83
84
85
86
87
88

    if (tokenAt(0).kind() == T_POUND) {
        enter(cpp_macro_start);
        m_tokenIndex = 1;
    }

    for (; m_tokenIndex < m_tokens.size(); ) {
        m_currentToken = tokenAt(m_tokenIndex);
        const int kind = m_currentToken.kind();

        switch (m_currentState.top().type) {
        case topmost_intro:
89
90
            tryDeclaration();
            break;
91
92
93

        case namespace_start:
            switch (kind) {
94
            case T_LBRACE:      enter(namespace_open); break;
95
            case T_SEMICOLON:
96
            case T_RBRACE:      leave(); break;
97
98
99
100
101
102
            } break;

        case namespace_open:
            if (tryDeclaration())
                break;
            switch (kind) {
103
            case T_RBRACE:      leave(); continue; // always nested in namespace_start
104
105
            } break;

106
107
108
109
110
111
112
113
114
115
116
117
118
119
        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;

120
121
122
        case class_start:
            switch (kind) {
            case T_SEMICOLON:   leave(); break;
123
            case T_LPAREN:      turnInto(declaration_start); continue; // "struct Foo bar() {"
124
            case T_LBRACE:      enter(class_open); break;
125
126
127
128
129
130
            } break;

        case class_open:
            if (tryDeclaration())
                break;
            switch (kind) {
131
            case T_RBRACE:      leave(); continue; // always nested in class_start
132
133
            } break;

134
135
136
137
138
        case access_specifier_start:
            switch (kind) {
            case T_COLON:       leave(); break;
            } break;

139
140
141
        case enum_start:
            switch (kind) {
            case T_SEMICOLON:   leave(); break;
142
            case T_LPAREN:      turnInto(declaration_start); continue; // "enum Foo bar() {"
143
144
145
146
147
148
149
            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;
150
151
152
153
154
            } break;

        case brace_list_open:
            switch (kind) {
            case T_RBRACE:      leave(); break;
155
            case T_LBRACE:      enter(brace_list_open); break;
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
            } 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;
172
            case T_GREATER_GREATER: leave(); leave(); break; // call leave twice to pop both template_param states
173
174
175
176
177
178
179
180
181
182
            } break;

        case operator_declaration:
            switch (kind) {
            case T_LPAREN:      break;
            default:            leave(); break;
            } break;

        case declaration_start:
            switch (kind) {
183
184
185
            case T_CLASS:
            case T_STRUCT:      turnInto(class_start); continue;
            case T_ENUM:        turnInto(enum_start); continue;
186
            case T_RBRACE:      leave(true); continue;
187
            case T_SEMICOLON:   leave(true); break;
188
            case T_EQUAL:       enter(assign_open_or_initializer); break;
189
            case T_LBRACE:      enter(defun_open); break;
190
            case T_COLON:       enter(member_init_open); enter(member_init_expected); break;
191
            case T_OPERATOR:    enter(operator_declaration); break;
192
            case T_GREATER_GREATER: break;
193
            default:            tryExpression(true); break;
194
195
            } break;

196
        case assign_open_or_initializer:
197
198
            switch (kind) {
            case T_LBRACE:      enter(brace_list_open); break;
199
200
            case T_RBRACE:      leave(true); continue;
            case T_SEMICOLON:   leave(); continue;
201
            case T_RPAREN:      leave(); continue;
202
            case T_COMMA:       leave(); continue;
203
            default:            enter(assign_open); continue;
204
205
206
207
            } break;

        case expression:
            switch (kind) {
208
            case T_RBRACE:      leave(true); continue;
209
210
211
212
213
214
215
            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;
216
217
                } else {
                    turnInto(substatement_open);
218
219
                }
                break;
220
221
222
223
224
225
226
            default:            tryExpression(); break;
            } break;

        case assign_open:
            switch (kind) {
            case T_RBRACE:      leave(true); continue;
            case T_SEMICOLON:   leave(); continue;
227
            case T_RPAREN:      leave(); continue;
228
            case T_COMMA:       leave(); continue;
229
            default:            tryExpression(); break;
230
231
            } break;

Flex Ferrum's avatar
Flex Ferrum committed
232
233
234
235
        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:
Sergio Ahumada's avatar
Sergio Ahumada committed
236
            case T_EQUAL:       turnInto(lambda_instroducer); break;              // ',' or '=' inside brackets can be only within lambda capture list
Flex Ferrum's avatar
Flex Ferrum committed
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
            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:            leave(); continue;
            } break;

        case lambda_declarator:
            switch (kind) {
            case T_LBRACE:      turnInto(substatement_open); /*tryStatement()*/; break;
            } break;

296
297
        case arglist_open:
            switch (kind) {
298
            case T_SEMICOLON:   leave(true); break;
Flex Ferrum's avatar
Flex Ferrum committed
299
            case T_LBRACE:      enter(brace_list_open); break;
300
            case T_RBRACE:      leave(true); continue;
301
            case T_RPAREN:      leave(); break;
302
            default:            tryExpression(); break;
303
304
            } break;

305
306
307
308
309
310
311
        case braceinit_open:
            switch (kind) {
            case T_RBRACE:      leave(); break;
            case T_RPAREN:      leave(); continue; // recover?
            default:            tryExpression(); break;
            } break;

312
313
314
315
316
        case ternary_op:
            switch (kind) {
            case T_RPAREN:
            case T_COMMA:
            case T_SEMICOLON:   leave(); continue; // always nested, propagate
317
            default:            tryExpression(); break;
318
319
320
            } break;

        case stream_op:
321
        case stream_op_cont:
322
            switch (kind) {
323
324
325
326
327
328
329
            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;
330
            case T_RPAREN:
331
            case T_COMMA:
332
            case T_SEMICOLON:   leave(); continue; // always nested, propagate
333
            default:            tryExpression(); break;
334
335
336
337
338
            } break;

        case member_init_open:
            switch (kind) {
            case T_LBRACE:      turnInto(defun_open); break;
339
340
341
342
343
344
345
346
            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:
347
348
349
350
351
352
            case T_SEMICOLON:   leave(); continue; // try to recover
            } break;

        case member_init:
            switch (kind) {
            case T_LBRACE:
353
354
355
            case T_LPAREN:      enter(member_init_nest_open); break;
            case T_RBRACE:
            case T_RPAREN:      leave(); break;
356
357
358
            case T_SEMICOLON:   leave(); continue; // try to recover
            } break;

359
        case member_init_nest_open:
360
            switch (kind) {
361
            case T_RBRACE:
362
363
            case T_RPAREN:      leave(); continue;
            case T_SEMICOLON:   leave(); continue; // try to recover
364
            default:            tryExpression(); break;
365
366
367
368
369
370
            } break;

        case defun_open:
            if (tryStatement())
                break;
            switch (kind) {
371
            case T_RBRACE:      leave(); leave(); break; // always nested in declaration_start
372
373
374
375
376
377
378
            } break;

        case switch_statement:
        case statement_with_condition:
        case if_statement:
            switch (kind) {
            case T_LPAREN:      enter(condition_open); break;
379
            default:            leave(true); continue;
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
            } 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();
397
            QTC_CHECK(false);
398
399
400
401
402
403
            leave(true);
            break;

        case do_statement:
            // ### shouldn't happen
            dump();
404
            QTC_CHECK(false);
405
406
407
408
409
            leave(true);
            break;

        case return_statement:
            switch (kind) {
410
            case T_RBRACE:      leave(true); continue;
411
412
413
414
415
416
417
418
419
420
            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;
421
            case T_RBRACE:      leave(true); continue;
422
423
424
425
426
            } break;

        case for_statement:
            switch (kind) {
            case T_LPAREN:      enter(for_statement_paren_open); break;
427
            default:            leave(true); continue;
428
429
430
431
432
433
434
435
436
            } 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;
437
            case T_RPAREN:      turnInto(for_statement_expression); continue;
438
439
440
441
442
443
            } break;

        case for_statement_condition:
            switch (kind) {
            case T_SEMICOLON:   turnInto(for_statement_expression); break;
            case T_LPAREN:      enter(condition_paren_open); break;
444
            case T_RPAREN:      turnInto(for_statement_expression); continue;
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
            } 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:      leave(); continue;
            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;
483
            switch (kind) {
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
            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;

Christian Kamm's avatar
Christian Kamm committed
501
502
503
504
505
506
        case label:
            switch (kind) {
            case T_COLON:       leave(); break;
            default:            leave(); continue; // shouldn't happen
            } break;

507
508
509
510
511
512
        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
513
                    && lexerState == 0) {
514
515
516
517
518
519
520
521
522
523
524
525
526
527
                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) {
528
                    if (previousMarker == -1) {
529
                        previousMarker = i;
530
                    } else {
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
                        previousPreviousMarker = i;
                        break;
                    }
                }
            }

            QStringRef 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;

567
568
569
570
571
572
573
        case string_open:
            if (!m_currentToken.isStringLiteral()) {
                leave();
                continue;
            }
            break;

574
575
576
577
578
579
580
581
582
583
584
585
586
        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
587
588
            && (lexerState == T_COMMENT
                || lexerState == T_DOXY_COMMENT)) {
589
590
591
592
593
594
595
596
597
598
599
600
601
        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);

602
    saveCurrentState(block);
603
604
}

605
void CodeFormatter::indentFor(const QTextBlock &block, int *indent, int *padding)
606
607
608
{
//    qDebug() << "indenting for" << block.blockNumber() + 1;

609
    restoreCurrentState(block.previous());
610
    correctIndentation(block);
611
612
    *indent = m_indentDepth;
    *padding = m_paddingDepth;
613
614
}

615
void CodeFormatter::indentForNewLineAfter(const QTextBlock &block, int *indent, int *padding)
616
617
{
    restoreCurrentState(block);
618
619
    *indent = m_indentDepth;
    *padding = m_paddingDepth;
620
621
622
623
624

    int lexerState = loadLexerState(block);
    m_tokens.clear();
    m_currentLine.clear();
    adjustIndent(m_tokens, lexerState, indent, padding);
625
626
}

627
void CodeFormatter::updateStateUntil(const QTextBlock &endBlock)
628
629
{
    QStack<State> previousState = initialState();
630
    QTextBlock it = endBlock.document()->firstBlock();
631
632

    // find the first block that needs recalculation
633
    for (; it.isValid() && it != endBlock; it = it.next()) {
634
635
        BlockData blockData;
        if (!loadBlockData(it, &blockData))
636
            break;
637
        if (blockData.m_blockRevision != it.revision())
638
            break;
639
640
        if (previousState.isEmpty() || blockData.m_beginState.isEmpty()
                || previousState != blockData.m_beginState)
641
            break;
642
        if (loadLexerState(it) == -1)
643
644
            break;

645
        previousState = blockData.m_endState;
646
    }
647
648
649
650
651

    if (it == endBlock)
        return;

    // update everthing until endBlock
652
653
654
    for (; it.isValid() && it != endBlock; it = it.next()) {
        recalculateStateAfter(it);
    }
655
656

    // invalidate everything below by marking the state in endBlock as invalid
657
658
659
660
    if (it.isValid()) {
        BlockData invalidBlockData;
        saveBlockData(&it, invalidBlockData);
    }
661
662
663
664
665
666
667
}

void CodeFormatter::updateLineStateChange(const QTextBlock &block)
{
    if (!block.isValid())
        return;

668
669
670
    BlockData blockData;
    if (loadBlockData(block, &blockData) && blockData.m_blockRevision == block.revision())
        return;
671
672
673

    recalculateStateAfter(block);

674
675
676
677
    // invalidate everything below by marking the next block's state as invalid
    QTextBlock next = block.next();
    if (!next.isValid())
        return;
678

679
    saveBlockData(&next, BlockData());
680
681
682
683
684
685
686
687
688
689
}

CodeFormatter::State CodeFormatter::state(int belowTop) const
{
    if (belowTop < m_currentState.size())
        return m_currentState.at(m_currentState.size() - 1 - belowTop);
    else
        return State();
}

690
691
692
693
694
const QVector<CodeFormatter::State> &CodeFormatter::newStatesThisLine() const
{
    return m_newStates;
}

695
696
697
698
699
int CodeFormatter::tokenIndex() const
{
    return m_tokenIndex;
}

700
int CodeFormatter::tokenCount() const
701
{
702
    return m_tokens.size();
703
704
705
706
707
708
709
}

const CPlusPlus::Token &CodeFormatter::currentToken() const
{
    return m_currentToken;
}

710
void CodeFormatter::invalidateCache(QTextDocument *document)
711
{
712
713
714
    if (!document)
        return;

715
    BlockData invalidBlockData;
716
    QTextBlock it = document->firstBlock();
717
    for (; it.isValid(); it = it.next()) {
718
        saveBlockData(&it, invalidBlockData);
719
720
721
722
723
724
    }
}

void CodeFormatter::enter(int newState)
{
    int savedIndentDepth = m_indentDepth;
725
726
727
    int savedPaddingDepth = m_paddingDepth;
    onEnter(newState, &m_indentDepth, &savedIndentDepth, &m_paddingDepth, &savedPaddingDepth);
    State s(newState, savedIndentDepth, savedPaddingDepth);
728
729
    m_currentState.push(s);
    m_newStates.push(s);
730
731
732
733
}

void CodeFormatter::leave(bool statementDone)
{
734
    QTC_ASSERT(m_currentState.size() > 1, return);
735
736
737
    if (m_currentState.top().type == topmost_intro)
        return;

738
739
740
    if (m_newStates.size() > 0)
        m_newStates.pop();

741
742
743
    // restore indent depth
    State poppedState = m_currentState.pop();
    m_indentDepth = poppedState.savedIndentDepth;
744
    m_paddingDepth = poppedState.savedPaddingDepth;
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772

    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);
773
    QTC_ASSERT(m_currentState.size() >= 1, return);
774

775
    adjustIndent(m_tokens, lexerState, &m_indentDepth, &m_paddingDepth);
776
777
778
}

bool CodeFormatter::tryExpression(bool alsoExpression)
Orgad Shaneh's avatar
Orgad Shaneh committed
779
{
780
781
782
783
784
785
    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;
786
    case T_LBRACE:          newState = braceinit_open; break;
787

788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
    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;

804
805
806
807
808
    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;
809
            if (type == arglist_open) { // likely a left-shift instead
810
811
812
813
814
815
816
                newState = -1;
                break;
            }
            if (type == topmost_intro
                    || type == substatement_open
                    || type == defun_open
                    || type == namespace_open
817
                    || type == extern_open
818
819
820
821
822
823
                    || type == class_open
                    || type == brace_list_open) {
                break;
            }
        }
        break;
Flex Ferrum's avatar
Flex Ferrum committed
824
825
826
    case T_LBRACKET:
        newState = lambda_instroducer_or_subscribtion;
        break;
827
828
    }

829
830
831
    if (m_currentToken.isStringLiteral())
        newState = string_open;

832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
    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:
848
    case T_Q_PRIVATE_PROPERTY:
849
850
851
852
853
854
855
856
857
858
    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) {
859
            const QStringRef tokenText = currentTokenText();
860
861
            if (tokenText.startsWith(QLatin1String("Q_"))
                    || tokenText.startsWith(QLatin1String("QT_"))
862
                    || tokenText.startsWith(QLatin1String("QML_"))
863
864
865
866
                    || tokenText.startsWith(QLatin1String("QDOC_"))) {
                enter(qt_like_macro);
                return true;
            }
Christian Kamm's avatar
Christian Kamm committed
867
868
869
870
            if (m_tokens.size() > 1 && m_tokens.at(1).kind() == T_COLON) {
                enter(label);
                return true;
            }
871
872
873
        }
        // fallthrough
    case T_CHAR:
874
875
    case T_CHAR16_T:
    case T_CHAR32_T:
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
    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_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;

901
902
903
904
    case T_NAMESPACE:
        enter(namespace_start);
        return true;

905
906
907
908
    case T_EXTERN:
        enter(extern_start);
        return true;

909
910
911
912
913
914
915
916
917
918
919
920
921
922
    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;

923
924
925
926
927
928
929
930
931
932
    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;

933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
    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);
}

996
997
998
999
1000
1001
1002
1003
1004
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++) {
1005
        if (m_currentLine[i] == tab)
1006
            col = ((col / m_tabSize) + 1) * m_tabSize;
1007
        else
1008
1009
1010
1011
1012
            col++;
    }
    return col;
}

1013
1014
QStringRef CodeFormatter::currentTokenText() const
{
Nikolai Kosjar's avatar
Nikolai Kosjar committed
1015
    return m_currentLine.midRef(m_currentToken.bytesBegin(), m_currentToken.bytes());
1016
1017
1018
1019
1020
1021
1022
1023
}

void CodeFormatter::turnInto(int newState)
{
    leave(false);
    enter(newState);
}

1024
void CodeFormatter::saveCurrentState(const QTextBlock &block)
1025
1026
1027
1028
{
    if (!block.isValid())
        return;

1029
1030
1031
1032
1033
    BlockData blockData;
    blockData.m_blockRevision = block.revision();
    blockData.m_beginState = m_beginState;
    blockData.m_endState = m_currentState;
    blockData.m_indentDepth = m_indentDepth;
1034
    blockData.m_paddingDepth = m_paddingDepth;
1035
1036
1037

    QTextBlock saveableBlock(block);
    saveBlockData(&saveableBlock, blockData);
1038
1039
}

1040
void CodeFormatter::restoreCurrentState(const QTextBlock &block)
1041
{
Orgad Shaneh's avatar
Orgad Shaneh committed
1042
    if (block.isValid()) {
1043
1044
1045
        BlockData blockData;
        if (loadBlockData(block, &blockData)) {
            m_indentDepth = blockData.m_indentDepth;
1046
            m_paddingDepth = blockData.m_paddingDepth;
1047
            m_currentState = blockData.m_endState;
1048
1049
1050
1051
1052
1053
1054
1055
            m_beginState = m_currentState;
            return;
        }
    }

    m_currentState = initialState();
    m_beginState = m_currentState;
    m_indentDepth = 0;
1056
    m_paddingDepth = 0;
1057
1058
1059
1060
1061
1062
}

QStack<CodeFormatter::State> CodeFormatter::initialState()
{
    static QStack<CodeFormatter::State> initialState;
    if (initialState.isEmpty())
1063
        initialState.push(State(topmost_intro, 0, 0));
1064
1065
1066
1067
1068
    return initialState;
}

int CodeFormatter::tokenizeBlock(const QTextBlock &block, bool *endedJoined)
{
1069
    int startState = loadLexerState(block.previous());
1070
1071
    if (block.blockNumber() == 0)
        startState = 0;
1072
    QTC_ASSERT(startState != -1, return 0);
1073

1074
1075
1076
1077
1078
1079
    LanguageFeatures features;
    features.qtEnabled = true;
    features.qtMocRunEnabled = true;
    features.qtKeywordsEnabled = true;
    features.objCEnabled = true;

1080
    SimpleLexer tokenize;
1081
    tokenize.setLanguageFeatures(features);
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092

    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();
mae's avatar
mae committed
1093
    BaseTextDocumentLayout::setLexerState(block, lexerState);
1094
1095
1096
    return lexerState;
}

1097
void CodeFormatter::dump() const
1098
{
1099
1100
    QMetaEnum metaEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("StateType"));

1101
1102
    qDebug() << "Current token index" << m_tokenIndex;
    qDebug() << "Current state:";
Friedemann Kleint's avatar
Friedemann Kleint committed
1103
    foreach (const State &s, m_currentState) {
1104
        qDebug() << metaEnum.valueToKey(s.type) << s.savedIndentDepth << s.savedPaddingDepth;
1105
1106
    }
    qDebug() << "Current indent depth:" << m_indentDepth;
1107
    qDebug() << "Current padding depth:" << m_paddingDepth;
1108
1109
}

1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120

namespace CppTools {
namespace Internal {
    class CppCodeFormatterData: public TextEditor::CodeFormatterData
    {
    public:
        CodeFormatter::BlockData m_data;
    };
}
}

1121
1122
1123
1124
QtStyleCodeFormatter::QtStyleCodeFormatter()
{
}

1125
1126
1127
1128
QtStyleCodeFormatter::QtStyleCodeFormatter(const TextEditor::TabSettings &tabSettings,
                                           const CppCodeStyleSettings &settings)
    : m_tabSettings(tabSettings)
    , m_styleSettings(settings)
1129
1130
1131
1132
{
    setTabSize(tabSettings.m_tabSize);
}

1133
void QtStyleCodeFormatter::setTabSettings(const TextEditor::TabSettings &tabSettings)
1134
{
1135
1136
    m_tabSettings = tabSettings;
    setTabSize(tabSettings.m_tabSize);
1137
1138
}

1139
void QtStyleCodeFormatter::setCodeStyleSettings(const CppCodeStyleSettings &settings)
1140
{
1141
    m_styleSettings = settings;
1142
1143
}

1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
void QtStyleCodeFormatter::saveBlockData(QTextBlock *block, const BlockData &data) const
{
    TextBlockUserData *userData = BaseTextDocumentLayout::userData(*block);
    CppCodeFormatterData *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 = BaseTextDocumentLayout::testUserData(block);
    if (!userData)
        return false;
    CppCodeFormatterData *cppData = static_cast<CppCodeFormatterData *>(userData->codeFormatterData());
    if (!cppData)
        return false;

    *data = cppData->m_data;
    return true;
}

void QtStyleCodeFormatter::saveLexerState(QTextBlock *block, int state) const
{
mae's avatar
mae committed
1170
    BaseTextDocumentLayout::setLexerState(*block, state);
1171
1172
1173
1174
}

int QtStyleCodeFormatter::loadLexerState(const QTextBlock &block) const
{
mae's avatar
mae committed
1175
    return BaseTextDocumentLayout::lexerState(block);
1176
1177
}

1178
1179
1180
1181
1182
1183
1184
1185
void QtStyleCodeFormatter::addContinuationIndent(int *paddingDepth) const
{
    if (*paddingDepth == 0)
        *paddingDepth = 2*m_tabSettings.m_indentSize;
    else
        *paddingDepth += m_tabSettings.m_indentSize;
}

1186
void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedIndentDepth, int *paddingDepth, int *savedPaddingDepth) const
1187
1188
1189
1190
{
    const State &parentState = state();
    const Token &tk = currentToken();
    const bool firstToken = (tokenIndex() == 0);
1191
    const bool lastToken = (tokenIndex() == tokenCount() - 1);
Nikolai Kosjar's avatar
Nikolai Kosjar committed
1192
1193
1194
1195
    const int tokenPosition = column(tk.bytesBegin());
    const int nextTokenPosition = lastToken ? tokenPosition + tk.bytes()
                                            : column(tokenAt(tokenIndex() + 1).bytesBegin());
    const int spaceOrNextTokenPosition = lastToken ? tokenPosition + tk.bytes() + 1
1196
                                                   : nextTokenPosition;
1197

1198
1199
1200
    if (shouldClearPaddingOnEnter(newState))
        *paddingDepth = 0;

1201
    switch (newState) {
1202
    case extern_start:
1203
    case namespace_start:
1204
        if (firstToken) {
1205
            *savedIndentDepth = tokenPosition;
1206
1207
            *indentDepth = tokenPosition;
        }
1208
1209
1210
1211
        break;

    case enum_start:
    case class_start:
1212
        if (firstToken) {
1213
            *savedIndentDepth = tokenPosition;
1214
1215
            *indentDepth = tokenPosition;
        }
1216
        *paddingDepth = 2*m_tabSettings.m_indentSize;
1217
1218
1219
1220
        break;

    case template_param:
        if (!lastToken)
1221
            *paddingDepth = nextTokenPosition-*indentDepth;
1222
1223
        else
            addContinuationIndent(paddingDepth);
1224
1225
1226
1227
1228
1229
1230
1231
        break;

    case statement_with_condition:
    case for_statement:
    case switch_statement:
    case if_statement:
    case return_statement:
        if (firstToken)
1232
            *indentDepth = *savedIndentDepth = tokenPosition;
1233
        *paddingDepth = 2*m_tabSettings.m_indentSize;
1234
1235
        break;

1236
    case declaration_start:
1237
        if (firstToken) {
1238
            *savedIndentDepth = tokenPosition;
1239
1240
            *indentDepth = *savedIndentDepth;
        }
1241
1242
1243
1244
        // 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) {
1245
                *paddingDepth = 2*m_tabSettings.m_indentSize;
1246
1247
1248
1249
1250
                break;
            }
        }
        break;

1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
    case assign_open:
        if (parentState.type == assign_open_or_initializer)
            break;
        // fallthrough
    case assign_open_or_initializer:
        if (!lastToken && m_styleSettings.alignAssignments)
            *paddingDepth = nextTokenPosition-*indentDepth;
        else
            *paddingDepth = 2*m_tabSettings.m_indentSize;
        break;

1262
1263
    case arglist_open:
    case condition_paren_open:
1264
    case member_init_nest_open:
1265
        if (!lastToken)
1266
            *paddingDepth = nextTokenPosition-*indentDepth;
1267
        else
1268
            addContinuationIndent(paddingDepth);
1269
1270
1271
1272
        break;

    case ternary_op:
        if (!lastToken)
1273
            *paddingDepth = spaceOrNextTokenPosition-*indentDepth;
1274
        else
1275
            addContinuationIndent(paddingDepth);
1276
1277
1278
        break;

    case stream_op:
1279
        *paddingDepth = spaceOrNextTokenPosition-*indentDepth;
1280
        break;
1281
1282
    case stream_op_cont:
        if (firstToken)
1283
            *savedPaddingDepth = *paddingDepth = spaceOrNextTokenPosition-*indentDepth;
1284
        break;
1285
1286

    case member_init_open:
1287
        // undo the continuation indent of the parent
1288
        *savedPaddingDepth = 0;
1289

1290
1291
        // The paddingDepth is the expected location of the ',' and
        // identifiers are padded +2 from that in member_init_expected.
1292
        if (firstToken)
1293
            *paddingDepth = tokenPosition-*indentDepth;
1294
        else
1295
1296
1297
1298
1299
            *paddingDepth = m_tabSettings.m_indentSize - 2;
        break;

    case member_init_expected:
        *paddingDepth += 2;
1300
1301
1302
        break;

    case member_init: