From 29a51f0a6144d06ee91013474a43265d4d7788eb Mon Sep 17 00:00:00 2001 From: Hansruedi Patzen Date: Tue, 13 Feb 2018 14:41:33 +0100 Subject: [PATCH] Bug 531098: [C++17] Add support for switch with initializer Change-Id: I046acd311cb99215798d2cbb8d30c2ef8ff2301d Signed-off-by: Hansruedi Patzen --- .../parser/tests/ast2/DOMLocationTests.java | 21 +++++++ .../cxx14/constexpr/SwitchStatementTests.java | 42 +++++++++++++ .../rewrite/ASTWriterStatementTestSource.awts | 21 +++++++ .../dom/ast/cpp/ICPPASTSwitchStatement.java | 32 +++++++++- .../dom/parser/cpp/CPPASTSwitchStatement.java | 29 ++++++++- .../dom/parser/cpp/GNUCPPSourceParser.java | 12 +++- .../parser/cpp/semantics/CPPSemantics.java | 9 ++- .../core/dom/parser/cpp/semantics/ExecIf.java | 8 +-- .../dom/parser/cpp/semantics/ExecSwitch.java | 14 +++-- .../rewrite/astwriter/StatementWriter.java | 4 ++ .../eclipse/cdt/internal/core/pdom/PDOM.java | 7 ++- .../formatter/CodeFormatterVisitor.java | 39 +++++++++--- .../cdt/ui/tests/text/CodeFormatterTest.java | 59 +++++++++++++++++++ 13 files changed, 270 insertions(+), 27 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationTests.java index c26b65b589a..5c423f46deb 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/DOMLocationTests.java @@ -52,6 +52,7 @@ import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression; @@ -703,6 +704,26 @@ public class DOMLocationTests extends AST2TestBase { assertSoleLocation(declarator, code.indexOf(rawDeclarator), rawDeclarator.length()); } + public void testSwitchInitStatement_1() throws Exception { + String code = "void foo() { switch (int i = 1; i) {} }"; //$NON-NLS-1$ + IASTTranslationUnit tu = parse(code, ParserLanguage.CPP); + ICPPASTFunctionDefinition definition = (ICPPASTFunctionDefinition) tu.getDeclarations()[0]; + IASTCompoundStatement body = (IASTCompoundStatement) definition.getBody(); + IASTSwitchStatement statement = (IASTSwitchStatement) body.getStatements()[0]; + String rawDeclarator = "switch (int i = 1; i) {}"; //$NON-NLS-1$ + assertSoleLocation(statement, code.indexOf(rawDeclarator), rawDeclarator.length()); + } + + public void testSwitchInitStatement_2() throws Exception { + String code = "void foo() { char c = 'a'; switch (; c) {} }"; //$NON-NLS-1$ + IASTTranslationUnit tu = parse(code, ParserLanguage.CPP); + ICPPASTFunctionDefinition definition = (ICPPASTFunctionDefinition) tu.getDeclarations()[0]; + IASTCompoundStatement body = (IASTCompoundStatement) definition.getBody(); + IASTSwitchStatement statement = (IASTSwitchStatement) body.getStatements()[1]; + String rawDeclarator = "switch (; c) {}"; //$NON-NLS-1$ + assertSoleLocation(statement, code.indexOf(rawDeclarator), rawDeclarator.length()); + } + public void testIfInitStatement_1() throws Exception { String code = "void foo() { if (int i = 1; i == 1) {} }"; //$NON-NLS-1$ IASTTranslationUnit tu = parse(code, ParserLanguage.CPP); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/SwitchStatementTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/SwitchStatementTests.java index b71ca340b80..7d6d1b03d0e 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/SwitchStatementTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/cxx14/constexpr/SwitchStatementTests.java @@ -244,4 +244,46 @@ public class SwitchStatementTests extends TestBase { public void testSwitchWithNestedContinueStatement() throws Exception { assertEvaluationEquals(3); } + + // constexpr int triple(int x) { + // return x * 3; + // } + // constexpr int f(int y) { + // switch(int x = triple(y); x) { + // case 9: + // return 1; + // case 12: + // return 2; + // case 15: + // return 3; + // default: + // return 4; + // } + // } + + // constexpr int x = f(5); + public void testDeclarationInSwitchInitStatement() throws Exception { + assertEvaluationEquals(3); + } + + // constexpr int triple(int x) { + // return x * 3; + // } + // constexpr int f(int y) { + // switch(; int x = triple(y)) { + // case 9: + // return 1; + // case 12: + // return 2; + // case 15: + // return 3; + // default: + // return 4; + // } + // } + + // constexpr int x = f(5); + public void testDeclarationInSwitchStatementControllerEmptyInit() throws Exception { + assertEvaluationEquals(3); + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts index 766d3c6e588..41cd52b2d28 100644 --- a/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts +++ b/core/org.eclipse.cdt.core.tests/resources/rewrite/ASTWriterStatementTestSource.awts @@ -400,4 +400,25 @@ void f() constexpr int k{42}; if constexpr (;k == 42){ } +} + +//!Switch with emtpy init statement +//%CPP +void f() +{ + constexpr int k{42}; + switch (;k){ + case 42: + break; + } +} + +//!Switch with init statement +//%CPP +void f() +{ + switch (constexpr int k{42};k){ + case 42: + break; + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTSwitchStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTSwitchStatement.java index 0bac682ae31..94dd4609e2b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTSwitchStatement.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPASTSwitchStatement.java @@ -12,6 +12,7 @@ package org.eclipse.cdt.core.dom.ast.cpp; import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.IScope; @@ -21,6 +22,15 @@ import org.eclipse.cdt.core.dom.ast.IScope; */ public interface ICPPASTSwitchStatement extends IASTSwitchStatement { + /** + * {@code INIT_STATEMENT} represents the relationship between an + * {@code ICPPASTSwitchStatement} and its nested {@code IASTStatement}. + * + * @since 6.5 + */ + public static final ASTNodeProperty INIT_STATEMENT = new ASTNodeProperty( + "ICPPASTSwitchStatement.INIT_STATEMENT - IASTStatement init-statement for ICPPASTSwitchStatement"); //$NON-NLS-1$ + /** * CONTROLLER_DECLARATION represents the relationship between an * IASTSwitchStatement and it's nested @@ -42,7 +52,27 @@ public interface ICPPASTSwitchStatement extends IASTSwitchStatement { * @param d IASTDeclaration */ public void setControllerDeclaration( IASTDeclaration d ); - + + /** + * Returns the init-statement for a switch. + * + * @return the init-statement, or null if the 'switch' statement doesn't + * have one. + * + * @since 6.5 + */ + public IASTStatement getInitializerStatement(); + + /** + * Sets the optional init-statement of an switch. + * + * @param statement this statement should either be a IASTSimpleDeclaration or a + * IASTExpressionStatement. + * + * @since 6.5 + */ + public void setInitializerStatement(IASTStatement statement); + /** * Get the IScope represented by this switch. * diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSwitchStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSwitchStatement.java index e331ab2b6bb..20068999c34 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSwitchStatement.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTSwitchStatement.java @@ -30,6 +30,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExecSwitch; */ public class CPPASTSwitchStatement extends CPPASTAttributeOwner implements ICPPASTSwitchStatement, ICPPExecutionOwner { private IScope scope; + private IASTStatement initStatement; private IASTExpression controllerExpression; private IASTDeclaration controllerDeclaration; private IASTStatement body; @@ -55,6 +56,8 @@ public class CPPASTSwitchStatement extends CPPASTAttributeOwner implements ICPPA @Override public CPPASTSwitchStatement copy(CopyStyle style) { CPPASTSwitchStatement copy = new CPPASTSwitchStatement(); + copy.setInitializerStatement(initStatement == null ? + null : initStatement.copy(style)); copy.setControllerDeclaration(controllerDeclaration == null ? null : controllerDeclaration.copy(style)); copy.setControllerExpression(controllerExpression == null ? @@ -63,6 +66,22 @@ public class CPPASTSwitchStatement extends CPPASTAttributeOwner implements ICPPA return copy(copy, style); } + @Override + public IASTStatement getInitializerStatement() { + return initStatement; + } + + @Override + public void setInitializerStatement(IASTStatement statement) { + assertNotFrozen(); + this.initStatement = statement; + if (statement != null) { + statement.setParent(this); + statement.setPropertyInParent(INIT_STATEMENT); + statement = null; + } + } + @Override public IASTExpression getControllerExpression() { return controllerExpression; @@ -105,6 +124,7 @@ public class CPPASTSwitchStatement extends CPPASTAttributeOwner implements ICPPA } if (!acceptByAttributeSpecifiers(action)) return false; + if (initStatement != null && !initStatement.accept(action)) return false; if (controllerExpression != null && !controllerExpression.accept(action)) return false; if (controllerDeclaration != null && !controllerDeclaration.accept(action)) return false; if (body != null && !body.accept(action)) return false; @@ -121,6 +141,12 @@ public class CPPASTSwitchStatement extends CPPASTAttributeOwner implements ICPPA @Override public void replace(IASTNode child, IASTNode other) { + if (initStatement == child) { + other.setParent(child.getParent()); + other.setPropertyInParent(child.getPropertyInParent()); + initStatement = (IASTStatement) other; + return; + } if (body == child) { other.setPropertyInParent(child.getPropertyInParent()); other.setParent(child.getParent()); @@ -162,6 +188,7 @@ public class CPPASTSwitchStatement extends CPPASTAttributeOwner implements ICPPA @Override public ICPPExecution getExecution() { + ICPPExecution initStmtExec = EvalUtil.getExecutionFromStatement(getInitializerStatement()); ICPPASTExpression controllerExpr = (ICPPASTExpression) getControllerExpression(); ICPPExecutionOwner controllerDecl = (ICPPExecutionOwner) getControllerDeclaration(); ICPPEvaluation controllerExprEval = controllerExpr != null ? controllerExpr.getEvaluation() : null; @@ -178,6 +205,6 @@ public class CPPASTSwitchStatement extends CPPASTAttributeOwner implements ICPPA for (int i = 0; i < bodyStmts.length; i++) { bodyStmtExecutions[i] = EvalUtil.getExecutionFromStatement(bodyStmts[i]); } - return new ExecSwitch(controllerExprEval, controllerDeclExec, bodyStmtExecutions); + return new ExecSwitch(initStmtExec, controllerExprEval, controllerDeclExec, bodyStmtExecutions); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index d3717ffe206..cbb9a201dbe 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -5377,6 +5377,17 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { int startOffset; startOffset = consume().getOffset(); consume(IToken.tLPAREN); + + ICPPASTSwitchStatement switch_statement = getNodeFactory().newSwitchStatement(); + // init-statement + IToken mark= mark(); + try { + IASTStatement statement = initStatement(); + switch_statement.setInitializerStatement(statement); + } catch (BacktrackException e) { + backup(mark); + } + IASTNode switch_condition = cppStyleCondition(IToken.tRPAREN); switch (LT(1)) { case IToken.tRPAREN: @@ -5389,7 +5400,6 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } IASTStatement switch_body = parseSwitchBody(); - ICPPASTSwitchStatement switch_statement = getNodeFactory().newSwitchStatement(); ((ASTNode) switch_statement).setOffsetAndLength(startOffset, (switch_body != null ? calculateEndOffset(switch_body) : LA(1).getEndOffset()) - startOffset); if (switch_condition instanceof IASTExpression) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 53ab4f75f1c..97c6db6177b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -1622,7 +1622,14 @@ public class CPPSemantics { nodes= new IASTNode[] {initDeclaration}; } } else if (parent instanceof ICPPASTSwitchStatement) { - nodes = new IASTNode[] { ((ICPPASTSwitchStatement) parent).getControllerDeclaration() }; + ICPPASTSwitchStatement ifStatement = (ICPPASTSwitchStatement) parent; + final IASTStatement initStatement = ifStatement.getInitializerStatement(); + final IASTDeclaration controllerDeclaration = ifStatement.getControllerDeclaration(); + if (initStatement != null) { + nodes = new IASTNode[] {initStatement, controllerDeclaration}; + } else { + nodes = new IASTNode[] {controllerDeclaration}; + } } else if (parent instanceof ICPPASTIfStatement) { ICPPASTIfStatement ifStatement = (ICPPASTIfStatement) parent; final IASTStatement initStatement = ifStatement.getInitializerStatement(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIf.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIf.java index 4c12afdafa3..bd3179e98bd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIf.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecIf.java @@ -32,12 +32,6 @@ public class ExecIf implements ICPPExecution { this.elseClauseExec = elseClauseExec; } - private void executeInitStatement(ActivationRecord record, ConstexprEvaluationContext context) { - if (initStmtExec != null) { - EvalUtil.executeStatement(initStmtExec, record, context); - } - } - private boolean conditionSatisfied(ActivationRecord record, ConstexprEvaluationContext context) { if (conditionExprEval != null) { return EvalUtil.conditionExprSatisfied(conditionExprEval, record, context); @@ -49,7 +43,7 @@ public class ExecIf implements ICPPExecution { @Override public ICPPExecution executeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) { - executeInitStatement(record, context); + EvalUtil.executeStatement(initStmtExec, record, context); if (conditionSatisfied(record, context)) { return EvalUtil.executeStatement(thenClauseExec, record, context); } else if (elseClauseExec != null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecSwitch.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecSwitch.java index 29fde99e858..bfab9d5d5fa 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecSwitch.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/ExecSwitch.java @@ -17,11 +17,13 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext; import org.eclipse.core.runtime.CoreException; public class ExecSwitch implements ICPPExecution { + private final ICPPExecution initStmtExec; private final ICPPEvaluation controllerExprEval; private final ExecSimpleDeclaration controllerDeclExec; private final ICPPExecution[] bodyStmtExecutions; - public ExecSwitch(ICPPEvaluation controllerExprEval, ExecSimpleDeclaration controllerDeclExec, ICPPExecution[] bodyStmtExecutions) { + public ExecSwitch(ICPPExecution initStmtExec, ICPPEvaluation controllerExprEval, ExecSimpleDeclaration controllerDeclExec, ICPPExecution[] bodyStmtExecutions) { + this.initStmtExec = initStmtExec; this.controllerExprEval = controllerExprEval; this.controllerDeclExec = controllerDeclExec; this.bodyStmtExecutions = bodyStmtExecutions; @@ -29,6 +31,7 @@ public class ExecSwitch implements ICPPExecution { @Override public ICPPExecution executeForFunctionCall(ActivationRecord record, ConstexprEvaluationContext context) { + EvalUtil.executeStatement(initStmtExec, record, context); final int caseIndex = getMatchingCaseIndex(record, context); for (int i = caseIndex; i < bodyStmtExecutions.length; ++i) { ICPPExecution stmtExec = bodyStmtExecutions[i]; @@ -72,6 +75,7 @@ public class ExecSwitch implements ICPPExecution { @Override public ICPPExecution instantiate(InstantiationContext context, int maxDepth) { + ICPPExecution newInitStmtExec = initStmtExec != null ? initStmtExec.instantiate(context, maxDepth) : null; ICPPEvaluation newControllerExprEval = controllerExprEval != null ? controllerExprEval.instantiate(context, maxDepth) : null; ExecSimpleDeclaration newControllerDeclExec = controllerDeclExec != null ? (ExecSimpleDeclaration) controllerDeclExec.instantiate(context, maxDepth) : null; ICPPExecution[] newBodyStmtExecutions = new ICPPExecution[bodyStmtExecutions.length]; @@ -85,15 +89,16 @@ public class ExecSwitch implements ICPPExecution { newBodyStmtExecutions[i] = newBodyStmtExec; } - if (newControllerExprEval == controllerExprEval && newControllerDeclExec == controllerDeclExec && !executionsDidChange) { + if (newInitStmtExec == initStmtExec && newControllerExprEval == controllerExprEval && newControllerDeclExec == controllerDeclExec && !executionsDidChange) { return this; } - return new ExecSwitch(newControllerExprEval, newControllerDeclExec, newBodyStmtExecutions); + return new ExecSwitch(newInitStmtExec, newControllerExprEval, newControllerDeclExec, newBodyStmtExecutions); } @Override public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { buffer.putShort(ITypeMarshalBuffer.EXEC_SWITCH); + buffer.marshalExecution(initStmtExec, includeValue); buffer.marshalEvaluation(controllerExprEval, includeValue); buffer.marshalExecution(controllerDeclExec, includeValue); buffer.putInt(bodyStmtExecutions.length); @@ -103,6 +108,7 @@ public class ExecSwitch implements ICPPExecution { } public static ICPPExecution unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException { + ICPPExecution initStmtExec = buffer.unmarshalExecution(); ICPPEvaluation controllerExprEval = buffer.unmarshalEvaluation(); ExecSimpleDeclaration controllerDeclExec = (ExecSimpleDeclaration) buffer.unmarshalExecution(); int len = buffer.getInt(); @@ -110,6 +116,6 @@ public class ExecSwitch implements ICPPExecution { for (int i = 0; i < bodyStmtExecutions.length; i++) { bodyStmtExecutions[i] = buffer.unmarshalExecution(); } - return new ExecSwitch(controllerExprEval, controllerDeclExec, bodyStmtExecutions); + return new ExecSwitch(initStmtExec, controllerExprEval, controllerDeclExec, bodyStmtExecutions); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java index ce6713198a7..013e03aa78b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java @@ -365,6 +365,10 @@ public class StatementWriter extends NodeWriter { scribe.noNewLines(); if (switchStatement instanceof ICPPASTSwitchStatement) { ICPPASTSwitchStatement cppSwitchStatement = (ICPPASTSwitchStatement) switchStatement; + IASTStatement initStatement = cppSwitchStatement.getInitializerStatement(); + if (initStatement != null) { + writeStatement(initStatement, false); + } if (cppSwitchStatement.getControllerDeclaration() == null) { cppSwitchStatement.getControllerExpression().accept(visitor); } else { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 127f9bf3628..9c2519c8dca 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -292,10 +292,11 @@ public class PDOM extends PlatformObject implements IPDOM { * * CDT 9.5 development (version not supported on the 9.4.x branch) * 212.0 - C++ constexpr if and if init-statement evaluation + * 213.0 - C++ switch init-statement evaluation */ - private static final int MIN_SUPPORTED_VERSION= version(212, 0); - private static final int MAX_SUPPORTED_VERSION= version(212, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(212, 0); + private static final int MIN_SUPPORTED_VERSION= version(213, 0); + private static final int MAX_SUPPORTED_VERSION= version(213, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(213, 0); private static int version(int major, int minor) { return (major << 16) + minor; diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java index 37c34403a62..7cec2794187 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java @@ -134,6 +134,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTRangeBasedForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeTemplateParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSwitchStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; @@ -3588,23 +3589,43 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor, return PROCESS_SKIP; } + private void beginSwitchClause() { + scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_switch); + if (preferences.insert_space_after_opening_paren_in_switch) { + scribe.space(); + } + } + private int visit(IASTSwitchStatement node) { final int headerIndent= scribe.numberOfIndentations; // 'switch' keyword if (!startsWithMacroExpansion(node)) { scribe.printNextToken(Token.t_switch); } - // Controller expression IASTExpression controllerExpression = node.getControllerExpression(); - if (!doNodesHaveSameOffset(node, controllerExpression)) { - scribe.printNextToken(Token.tLPAREN, preferences.insert_space_before_opening_paren_in_switch); - if (preferences.insert_space_after_opening_paren_in_switch) { - scribe.space(); + try { + // optional init-statement + if(node instanceof ICPPASTSwitchStatement) { + IASTStatement initStatement = ((ICPPASTSwitchStatement) node).getInitializerStatement(); + if (initStatement != null) { + beginSwitchClause(); + fHasClauseInitStatement = true; + initStatement.accept(this); + if (preferences.insert_space_after_semicolon_in_for) { + scribe.space(); + } + } } - } - controllerExpression.accept(this); - if (peekNextToken() == Token.tRPAREN) { - scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_switch); + // Controller expression + if (!doNodesHaveSameOffset(node, controllerExpression) && !fHasClauseInitStatement) { + beginSwitchClause(); + } + controllerExpression.accept(this); + if (peekNextToken() == Token.tRPAREN) { + scribe.printNextToken(Token.tRPAREN, preferences.insert_space_before_closing_paren_in_switch); + } + } finally { + fHasClauseInitStatement = false; } // switch body String brace_position = preferences.brace_position_for_switch; diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java index 7477575c0f8..0b56b5b6905 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CodeFormatterTest.java @@ -3312,4 +3312,63 @@ public class CodeFormatterTest extends BaseUITestCase { public void testIfInitStatementFormat_4() throws Exception { assertFormatterResult(); } + + //void foo() { + // switch (constexpr bool k = true; k) { + // } + //} + + //void foo() { + // switch (constexpr bool k = true; k) { + // } + //} + + public void testSwitchInitStatementFormat_1() throws Exception { + assertFormatterResult(); + } + + //void foo() { + // switch + // (constexpr bool k = true; k) { + // } + //} + + //void foo() { + // switch (constexpr bool k = true; k) { + // } + //} + public void testSwitchInitStatementFormat_2() throws Exception { + assertFormatterResult(); + } + + //void foo() { + // switch + // + // + // (constexpr bool k = true; k) { + // } + //} + + //void foo() { + // switch + // + // (constexpr bool k = true; k) { + // } + //} + public void testSwitchInitStatementFormat_3() throws Exception { + assertFormatterResult(); + } + + //void foo() { + // switch (constexpr bool k = true;k) { + // } + //} + + //void foo() { + // switch (constexpr bool k = true; k) { + // } + //} + public void testSwitchInitStatementFormat_4() throws Exception { + assertFormatterResult(); + } }