QmlJS indenter: Fix braceless switch/try/with bindings.

Change-Id: Iee25f3f9ec38b1b7fc2697f390386c9a60cb8347
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
Christian Kamm
2011-12-01 15:00:29 +01:00
parent 855e4eac4f
commit 69d6a508d3
3 changed files with 169 additions and 45 deletions

View File

@@ -156,6 +156,9 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
switch (kind) {
case Semicolon: leave(true); break;
case If: enter(if_statement); break;
case With: enter(statement_with_condition); break;
case Try: enter(try_statement); break;
case Switch: enter(switch_statement); break;
case LeftBrace: enter(jsblock_open); break;
case On:
case As:
@@ -377,14 +380,18 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
} break;
case maybe_else:
if (kind == Else) {
turnInto(else_clause);
enter(substatement);
break;
} else {
leave(true);
continue;
}
switch (kind) {
case Else: turnInto(else_clause); enter(substatement); break;
default: leave(true); continue;
} break;
case maybe_catch_or_finally:
dump();
switch (kind) {
case Catch: turnInto(catch_statement); break;
case Finally: turnInto(finally_statement); break;
default: leave(true); continue;
} break;
case else_clause:
// ### shouldn't happen
@@ -407,6 +414,7 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
} break;
case switch_statement:
case catch_statement:
case statement_with_condition:
switch (kind) {
case LeftParenthesis: enter(statement_with_condition_paren_open); break;
@@ -420,7 +428,8 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block)
case RightParenthesis: turnInto(substatement); break;
} break;
case statement_with_block:
case try_statement:
case finally_statement:
switch (kind) {
case LeftBrace: enter(jsblock_open); break;
default: leave(true); break;
@@ -633,6 +642,8 @@ void CodeFormatter::enter(int newState)
m_currentState.push(s);
m_newStates.push(s);
//qDebug() << "enter state" << stateToString(newState);
if (newState == bracket_open)
enter(bracket_element_start);
}
@@ -652,10 +663,10 @@ void CodeFormatter::leave(bool statementDone)
int topState = m_currentState.top().type;
//qDebug() << "left state" << stateToString(poppedState.type) << ", now in state" << stateToString(topState);
// if statement is done, may need to leave recursively
if (statementDone) {
if (!isExpressionEndState(topState))
leave(true);
if (topState == if_statement) {
if (poppedState.type != maybe_else)
enter(maybe_else);
@@ -665,6 +676,15 @@ void CodeFormatter::leave(bool statementDone)
// leave the else *and* the surrounding if, to prevent another else
leave();
leave(true);
} else if (topState == try_statement) {
if (poppedState.type != maybe_catch_or_finally
&& poppedState.type != finally_statement) {
enter(maybe_catch_or_finally);
} else {
leave(true);
}
} else if (!isExpressionEndState(topState)) {
leave(true);
}
}
}
@@ -740,8 +760,7 @@ bool CodeFormatter::tryStatement()
enter(case_start);
return true;
case Try:
case Finally:
enter(statement_with_block);
enter(try_statement);
return true;
case LeftBrace:
enter(jsblock_open);
@@ -787,9 +806,7 @@ bool CodeFormatter::isExpressionEndState(int type) const
type == topmost_intro ||
type == top_js ||
type == objectdefinition_open ||
type == if_statement ||
type == do_statement ||
type == else_clause ||
type == jsblock_open ||
type == substatement_open ||
type == bracket_open ||
@@ -988,16 +1005,20 @@ CodeFormatter::TokenKind CodeFormatter::extendedTokenKind(const QmlJS::Token &to
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;
qDebug() << stateToString(s.type) << s.savedIndentDepth;
}
qDebug() << "Current indent depth:" << m_indentDepth;
}
QString CodeFormatter::stateToString(int type) const
{
const QMetaEnum &metaEnum = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("StateType"));
return metaEnum.valueToKey(type);
}
QtStyleCodeFormatter::QtStyleCodeFormatter()
: m_indentSize(4)
{}
@@ -1158,7 +1179,9 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
case statement_with_condition:
case statement_with_block:
case try_statement:
case catch_statement:
case finally_statement:
case if_statement:
case do_statement:
case switch_statement:
@@ -1176,14 +1199,13 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd
}
break;
case maybe_else: {
// set indent to outermost braceless savedIndent
int outermostBraceless = 0;
while (isBracelessState(state(outermostBraceless + 1).type))
++outermostBraceless;
*indentDepth = state(outermostBraceless).savedIndentDepth;
// this is where the else should go, if one appears - aligned to if_statement
*savedIndentDepth = state().savedIndentDepth;
case maybe_else:
case maybe_catch_or_finally: {
// set indent to where leave(true) would put it
int lastNonEndState = 0;
while (!isExpressionEndState(state(lastNonEndState + 1).type))
++lastNonEndState;
*indentDepth = state(lastNonEndState).savedIndentDepth;
break;
}
@@ -1278,7 +1300,7 @@ void QtStyleCodeFormatter::adjustIndent(const QList<Token> &tokens, int startLex
case Else:
if (topState.type == maybe_else) {
*indentDepth = topState.savedIndentDepth;
*indentDepth = state(1).savedIndentDepth;
} else if (topState.type == expression_maybe_continuation) {
bool hasElse = false;
for (int i = 1; state(i).type != topmost_intro; ++i) {
@@ -1297,6 +1319,12 @@ void QtStyleCodeFormatter::adjustIndent(const QList<Token> &tokens, int startLex
}
break;
case Catch:
case Finally:
if (topState.type == maybe_catch_or_finally)
*indentDepth = state(1).savedIndentDepth;
break;
case Colon:
if (topState.type == ternary_op) {
*indentDepth -= 2;

View File

@@ -167,10 +167,13 @@ public: // must be public to make Q_GADGET introspection work
return_statement, // After 'return'
throw_statement, // After 'throw'
statement_with_condition, // After the 'for', 'while', 'catch', ... token
statement_with_condition, // After the 'for', 'while', ... token
statement_with_condition_paren_open, // While inside the (...)
statement_with_block, // try, finally
try_statement, // after 'try'
catch_statement, // after 'catch', nested in try_statement
finally_statement, // after 'finally', nested in try_statement
maybe_catch_or_finally, // after ther closing '}' of try_statement and catch_statement, nested in try_statement
do_statement, // after 'do'
do_statement_while_paren_open, // after '(' in while clause
@@ -278,6 +281,7 @@ protected:
bool isExpressionEndState(int type) const;
void dump() const;
QString stateToString(int type) const;
private:
void recalculateStateAfter(const QTextBlock &block);

View File

@@ -61,6 +61,11 @@ private Q_SLOTS:
void ifBinding1();
void ifBinding2();
void ifBinding3();
void withBinding();
void tryBinding1();
void tryBinding2();
void tryBinding3();
void switchBinding();
void ifStatementWithoutBraces1();
void ifStatementWithoutBraces2();
void ifStatementWithoutBraces3();
@@ -98,7 +103,6 @@ private Q_SLOTS:
void labelledStatements3();
void json1();
void multilineTernaryInProperty();
void bug1();
void multilineString();
void bug1();
};
@@ -538,6 +542,108 @@ void tst_QMLCodeFormatter::ifBinding3()
checkIndent(data);
}
void tst_QMLCodeFormatter::withBinding()
{
QList<Line> data;
data << Line("Rectangle {")
<< Line(" foo: with(pos) { x }")
<< Line(" foo: with(pos) {")
<< Line(" x")
<< Line(" }")
<< Line(" foo: 12")
<< Line("}")
;
checkIndent(data);
}
void tst_QMLCodeFormatter::tryBinding1()
{
QList<Line> data;
data << Line("Rectangle {")
<< Line(" foo: try { x } finally { y }")
<< Line(" foo: try {")
<< Line(" x")
<< Line(" } finally {")
<< Line(" y")
<< Line(" }")
<< Line(" foo: try {")
<< Line(" x")
<< Line(" }")
<< Line(" finally {")
<< Line(" y")
<< Line(" }")
<< Line(" foo: 12")
<< Line("}")
;
checkIndent(data);
}
void tst_QMLCodeFormatter::tryBinding2()
{
QList<Line> data;
data << Line("Rectangle {")
<< Line(" foo: try { x } catch (x) { y }")
<< Line(" foo: try {")
<< Line(" x")
<< Line(" } catch (e) {")
<< Line(" e")
<< Line(" }")
<< Line(" foo: try {")
<< Line(" x")
<< Line(" }")
<< Line(" catch (e) {")
<< Line(" e")
<< Line(" }")
<< Line(" foo: 12")
<< Line("}")
;
checkIndent(data);
}
void tst_QMLCodeFormatter::tryBinding3()
{
QList<Line> data;
data << Line("Rectangle {")
<< Line(" foo: try { x } catch (x) { y } finally { z }")
<< Line(" foo: try {")
<< Line(" x")
<< Line(" } catch (e) {")
<< Line(" e")
<< Line(" } finally {")
<< Line(" z")
<< Line(" }")
<< Line(" foo: try {")
<< Line(" x")
<< Line(" }")
<< Line(" catch (e) {")
<< Line(" e")
<< Line(" }")
<< Line(" finally {")
<< Line(" z")
<< Line(" }")
<< Line(" foo: 12")
<< Line("}")
;
checkIndent(data);
}
void tst_QMLCodeFormatter::switchBinding()
{
QList<Line> data;
data << Line("Rectangle {")
<< Line(" foo: switch (a) {")
<< Line(" case 1:")
<< Line(" x; break")
<< Line(" case 2:")
<< Line(" case 3:")
<< Line(" return y")
<< Line(" }")
<< Line(" foo: 12")
<< Line("}")
;
checkIndent(data);
}
void tst_QMLCodeFormatter::ifStatementWithoutBraces1()
{
QList<Line> data;
@@ -1301,20 +1407,6 @@ void tst_QMLCodeFormatter::multilineTernaryInProperty()
checkIndent(data);
}
void tst_QMLCodeFormatter::bug1()
{
QList<Line> data;
data << Line("Item {")
<< Line(" x: {")
<< Line(" if (a==a) {}")
<< Line(" else (b==b) {}")
<< Line(" foo()")
<< Line(" }")
<< Line("}")
;
checkIndent(data);
}
void tst_QMLCodeFormatter::multilineString()
{
QList<Line> data;