From 191094c758ae97c517952a2a038745b7581b6464 Mon Sep 17 00:00:00 2001 From: Dylan Sturgeon Date: Tue, 6 Oct 2020 16:57:56 -0700 Subject: [PATCH] Handle #if clauses inside of switch statements. The special IfConfigDecl, aka `#if`, can exist in the `cases` of a SwitchStmtSyntax because the `#if` "wraps" one or more switch cases. These weren't being considered for the purposes of indenting the cases. There were also no breaks between the switch statement's left brace and `#if` when `#if` was the first "case" which caused malformed code. I have opted to treat `indentSwitchCaseLabels` as also indenting the `#if` cases in a switch statement, because that makes the `#if` here consistent with other locations. --- .../TokenStreamCreator.swift | 11 +++ .../SwitchStmtTests.swift | 95 +++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift b/Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift index 1b7eb32a0..a6d50aec6 100644 --- a/Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift +++ b/Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift @@ -640,6 +640,17 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor { before(node.leftBrace, tokens: .break(.reset)) after(node.leftBrace, tokens: .close) + // An if-configuration clause around a switch-case encloses the case's node, so an + // if-configuration clause requires a break here in order to be allowed on a new line. + for ifConfigDecl in node.cases.filter({ $0.is(IfConfigDeclSyntax.self) }) { + if config.indentSwitchCaseLabels { + before(ifConfigDecl.firstToken, tokens: .break(.open)) + after(ifConfigDecl.lastToken, tokens: .break(.close, size: 0)) + } else { + before(ifConfigDecl.firstToken, tokens: .break(.same)) + } + } + let newlines: NewlineBehavior = areBracesCompletelyEmpty(node, contentsKeyPath: \.cases) ? .elective : .soft before(node.rightBrace, tokens: .break(.same, size: 0, newlines: newlines)) diff --git a/Tests/SwiftFormatPrettyPrintTests/SwitchStmtTests.swift b/Tests/SwiftFormatPrettyPrintTests/SwitchStmtTests.swift index 44f51097c..365e8ce36 100644 --- a/Tests/SwiftFormatPrettyPrintTests/SwitchStmtTests.swift +++ b/Tests/SwiftFormatPrettyPrintTests/SwitchStmtTests.swift @@ -1,3 +1,5 @@ +import SwiftFormatConfiguration + final class SwitchStmtTests: PrettyPrintTestCase { func testBasicSwitch() { let input = @@ -332,4 +334,97 @@ final class SwitchStmtTests: PrettyPrintTestCase { assertPrettyPrintEqual(input: input, expected: expected, linelength: 20) } + + func testConditionalCases() { + let input = + """ + switch foo { + #if CONDITION_A + case bar: + callForBar() + #endif + case baz: + callForBaz() + } + switch foo2 { + case bar2: + callForBar() + #if CONDITION_B + case baz2: + callForBaz() + #endif + } + """ + + let expected = + """ + switch foo { + #if CONDITION_A + case bar: + callForBar() + #endif + case baz: + callForBaz() + } + switch foo2 { + case bar2: + callForBar() + #if CONDITION_B + case baz2: + callForBaz() + #endif + } + + """ + + assertPrettyPrintEqual(input: input, expected: expected, linelength: 40) + } + + func testConditionalCasesIndenting() { + let input = + """ + switch foo { + #if CONDITION_A + case bar: + callForBar() + #endif + case baz: + callForBaz() + } + switch foo2 { + case bar2: + callForBar() + #if CONDITION_B + case baz2: + callForBaz() + #endif + } + """ + + let expected = + """ + switch foo { + #if CONDITION_A + case bar: + callForBar() + #endif + case baz: + callForBaz() + } + switch foo2 { + case bar2: + callForBar() + #if CONDITION_B + case baz2: + callForBaz() + #endif + } + + """ + + var configuration = Configuration() + configuration.indentSwitchCaseLabels = true + assertPrettyPrintEqual( + input: input, expected: expected, linelength: 40, configuration: configuration) + } }